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

intermediate🐍 Python2026-06-19| Python 3.8+, Flask 2.x / 3.x, mọi hệ điều hành (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

Bạn đang gọi current_app, g, hoặc một context-local của Flask từ nơi Flask không thiết lập cho bạn — một background thread, một script, một Celery task. Hãy tự push context:

with app.app_context():
    # code của bạn ở đây
    result = db.session.query(User).all()

Thread, Celery task và scheduled job mỗi loại cần cách xử lý hơi khác nhau. Hãy chuyển đến phần phù hợp với trường hợp của bạn.

Lỗi đầy đủ

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 thường in thêm một dòng thứ hai xác định đối tượng cụ thể — current_app, g, url_for(), hoặc một model Flask-SQLAlchemy. Dòng thứ hai đó là nơi bắt đầu debug.

Nguyên nhân gốc rễ

Bên dưới, Flask duy trì một context-local stack — một stack cho mỗi thread — lưu trữ app hiện tại và request hiện tại. Mỗi HTTP request đến sẽ push hai thứ lên stack đó: một application context và một request context. Các view function của bạn nhận cả hai miễn phí.

Tuy nhiên, khi bước ra ngoài vòng đời của request đó, stack sẽ trống. Các nguyên nhân phổ biến:

  • Một background thread được tạo bằng threading.Thread
  • Một Celery hoặc RQ worker task
  • Một Python script độc lập import các model của bạn
  • Một test pytest không có app context fixture
  • Một scheduled job của APScheduler hoặc Flask-APScheduler
  • Một Flask CLI command chạy như Python script thông thường thay vì qua flask <command>

Không cái nào trong số này đi qua vòng đời request của Flask, vì vậy không có gì trên stack cả.

Fix 1 — Bọc lời gọi trong app.app_context() (phổ biến nhất)

Bạn có tham chiếu trực tiếp đến đối tượng app? Một context manager giải quyết vấn đề chỉ trong hai dòng:

from myapp import create_app

app = create_app()

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

Script độc lập, tác vụ quản trị, di chuyển dữ liệu một lần — pattern này bao phủ tất cả.

Fix 2 — Background thread

Context local không vượt qua ranh giới thread. Mỗi thread mới bắt đầu với stack trống, vì vậy bạn cần push một context mới bên trong hàm thread:

import threading
from flask import current_app

def background_job(app):
    with app.app_context():
        # current_app hoạt động ở đây
        print(current_app.config["DATABASE_URI"])

# Truyền đối tượng app thực — không phải current_app
thread = threading.Thread(target=background_job, args=(app,))
thread.start()

Luôn truyền app, không phải current_app. current_app là một proxy chỉ phân giải được bên trong context đang hoạt động. Truyền nó sang thread khác và nó sẽ lỗi ngay lập tức.

Fix 3 — Celery task

Celery worker là các tiến trình riêng biệt, hoàn toàn không có Flask context. Cách sạch nhất là tạo một class Task tùy chỉnh bọc mỗi lời gọi task trong một 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+ có sẵn tích hợp Celery built-in. Xem hướng dẫn Flask + Celery chính thức để biết pattern factory init_celery(app) — nó xử lý việc kết nối này cho bạn.

Fix 4 — pytest test

Push context qua một fixture và yield từ bên trong nó. Mỗi test nhận fixture sẽ chạy bên trong một app context đang hoạt động:

# 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()

yield bên trong khối context là chi tiết quan trọng — setup, thân test và teardown đều chạy trong cùng một context đang hoạt động.

Fix 5 — APScheduler / Flask-APScheduler job

Scheduled job kích hoạt ngoài vòng đời request. Với Flask-APScheduler, truy cập app qua scheduler.app và push một context mới bên trong hàm job:

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 command

Các command được đăng ký với @app.cli.command sẽ được push app context tự động khi bạn chạy chúng qua flask <command>. Không cần thiết lập thêm.

Bẫy ở đây: chạy file trực tiếp bằng python seed_db.py bỏ qua Flask CLI hoàn toàn, vì vậy không có context nào được push. Luôn dùng CLI entry point:

@app.cli.command("seed-db")
def seed_db():
    # app context đã được kích hoạt — không cần push thêm
    db.session.add(AdminUser(email="admin@example.com"))
    db.session.commit()
    click.echo("Done.")

Chạy bằng flask seed-db, không phải python seed_db.py.

Xác minh

Sau khi áp dụng một fix, hãy chạy lại đường dẫn code bị lỗi. RuntimeError sẽ biến mất. Thêm một kiểm tra nhanh bên trong khối context để xác nhận:

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

Với Flask-SQLAlchemy, xác nhận session cũng đang hoạt động:

with app.app_context():
    from myapp.models import User
    count = User.query.count()
    print(f"{count} users trong DB — context đang hoạt động")

Tham khảo nhanh

Tình huốngCách fix

Script độc lập`with app.app_context():`
Background threadTruyền `app` vào thread, push bên trong
Celery taskClass `Task` tùy chỉnh hoặc helper Flask 2.3+
pytestApp fixture với `with app.app_context(): yield`
APScheduler job`with scheduler.app.app_context():`
Flask CLI commandDùng `flask <command>` — context được push tự động

Đọc thêm

Related Error Notes