Fix 'RuntimeError: Working outside of application context' in Flask

intermediate🐍 Python2026-06-19| Python 3.8+, Flask 2.x / 3.x, any OS (Linux, macOS, Windows)

Error Message

RuntimeError: Working outside of application context. This typically means that you attempted to use functionality that needed to interface with the current application object in some way.
#flask#python#app-context#runtimeerror

TL;DR

You're calling current_app, g, or another Flask context-local from somewhere Flask didn't set up for you β€” a background thread, a script, a Celery task. Push the context yourself:

with app.app_context():
    # your code here
    result = db.session.query(User).all()

Threads, Celery tasks, and scheduled jobs each need a slightly different approach. Jump to whichever section matches your situation.

The full error

RuntimeError: Working outside of application context. This typically means that you attempted to use functionality that needed to interface with the current application object in some way.

Flask often prints a second line identifying the exact object β€” current_app, g, url_for(), or a Flask-SQLAlchemy model. That second line is where to start debugging.

Root cause

Under the hood, Flask keeps a context-local stack β€” one per thread β€” holding the current app and current request. Every incoming HTTP request pushes two things onto that stack: an application context and a request context. Your view functions get both for free.

Step outside that request lifecycle, though, and the stack is empty. Common culprits:

  • A background thread spawned with threading.Thread
  • A Celery or RQ worker task
  • A standalone Python script that imports your models
  • A pytest test with no app context fixture
  • An APScheduler or Flask-APScheduler scheduled job
  • A Flask CLI command run as a plain Python script instead of via flask <command>

None of these go through Flask's request lifecycle, so there's nothing on the stack.

Fix 1 β€” Wrap the call in app.app_context() (most common)

Got a direct reference to the app object? A context manager solves it in two lines:

from myapp import create_app

app = create_app()

with app.app_context():
    from myapp.models import User
    users = User.query.all()
    print(users)

Standalone scripts, management tasks, one-off data migrations β€” this pattern covers all of them.

Fix 2 β€” Background threads

Context locals don't cross thread boundaries. Each new thread starts with an empty stack, so you need to push a fresh context inside the thread function:

import threading
from flask import current_app

def background_job(app):
    with app.app_context():
        # current_app works here
        print(current_app.config["DATABASE_URI"])

# Pass the real app object β€” not current_app
thread = threading.Thread(target=background_job, args=(app,))
thread.start()

Always pass app, not current_app. current_app is a proxy that only resolves inside an active context. Pass it to another thread and it explodes immediately.

Fix 3 β€” Celery tasks

Celery workers are separate processes with no Flask context at all. The cleanest fix is a custom Task base class that wraps every task call in an app context:

# celery_app.py
from celery import Task
from myapp import create_app

class FlaskTask(Task):
    def __call__(self, *args, **kwargs):
        with app.app_context():
            return super().__call__(*args, **kwargs)

app = create_app()
celery = app.extensions["celery"]
celery.Task = FlaskTask

Flask 2.3+ includes a built-in Celery integration. Check the official Flask + Celery tutorial for the init_celery(app) factory pattern β€” it handles this wiring for you.

Fix 4 β€” pytest tests

Push the context via a fixture and yield from inside it. Every test that receives the fixture runs inside a live app context:

# conftest.py
import pytest
from myapp import create_app, db as _db

@pytest.fixture()
def app():
    app = create_app({"TESTING": True, "SQLALCHEMY_DATABASE_URI": "sqlite:///:memory:"})
    with app.app_context():
        _db.create_all()
        yield app
        _db.drop_all()

@pytest.fixture()
def client(app):
    return app.test_client()

The yield inside the context block is the key detail β€” setup, test body, and teardown all run within the same active context.

Fix 5 β€” APScheduler / Flask-APScheduler jobs

Scheduled jobs fire outside the request cycle. With Flask-APScheduler, reach the app via scheduler.app and push a fresh context inside the job function:

from flask_apscheduler import APScheduler

scheduler = APScheduler()

@scheduler.task("cron", id="cleanup", hour=2)
def cleanup_job():
    with scheduler.app.app_context():
        from myapp.models import Session
        Session.query.filter(Session.expired == True).delete()
        db.session.commit()

Fix 6 β€” Flask CLI commands

Commands registered with @app.cli.command get an app context pushed automatically when you run them through flask <command>. No extra setup needed.

The trap: running the file directly with python seed_db.py skips the Flask CLI entirely, so no context is pushed. Always use the CLI entry point:

@app.cli.command("seed-db")
def seed_db():
    # app context is already active β€” no extra push needed
    db.session.add(AdminUser(email="admin@example.com"))
    db.session.commit()
    click.echo("Done.")

Run it with flask seed-db, not python seed_db.py.

Verification

Once you've applied a fix, re-run the failing code path. The RuntimeError should be gone. Add a quick sanity check inside the context block to confirm:

with app.app_context():
    from flask import current_app
    assert current_app._get_current_object() is app
    print("App context OK:", current_app.name)

For Flask-SQLAlchemy, confirm the session is alive too:

with app.app_context():
    from myapp.models import User
    count = User.query.count()
    print(f"{count} users in DB β€” context is live")

Quick reference

ScenarioFix

Standalone script`with app.app_context():`
Background threadPass `app` to thread, push inside
Celery taskCustom `Task` base class or Flask 2.3+ helper
pytestApp fixture with `with app.app_context(): yield`
APScheduler job`with scheduler.app.app_context():`
Flask CLI commandUse `flask <command>` β€” context is automatic

Further reading

Related Error Notes