pallets/flask · error · RuntimeError

'after_this_request' can only be used when a request…

Error message

'after_this_request' can only be used when a request context is active, such as in a view function.

What it means

after_this_request(f) reads the current app context from _cv_app. If ctx is None (no app context) or ctx.has_request is False (an app context is active but no request is bound to it), it raises RuntimeError. The function only makes sense within an active request because it queues f onto the current request's after-request chain.

Solutions

  1. Move the after_this_request call inside a view function where a request context is active.
  2. For background work, wrap the worker in copy_current_request_context and call after_this_request from within that copied context.
  3. In tests, push a request context with app.test_request_context() before invoking code that uses after_this_request.

Example fix

# before
@app.route('/')
def index():
    return 'hi'

after_this_request(add_header)  # at module level -> RuntimeError

# after
@app.route('/')
def index():
    after_this_request(add_header)
    return 'hi'
Defensive patterns

Strategy: type-guard

Validate before calling

from flask import has_request_context

def safe_after_this_request(f):
    if not has_request_context():
        raise RuntimeError('after_this_request requires a request context')
    from flask import after_this_request
    return after_this_request(f)

Type guard

from flask import has_request_context

def in_request_context() -> bool:
    return has_request_context()

Try / catch

try:
    after_this_request(add_header)
except RuntimeError:
    # queue the work another way, e.g. store on g or defer
    pass

Prevention

When it happens

Trigger: Calling after_this_request(...) outside a view function—e.g. at import time, in a background thread without a request context, in a shell command, or in an app-context-only block (with app.app_context() but no test_request_context/request). The check is ctx is None or not ctx.has_request.

Common situations: Registering a cleanup hook from a module-level function. Using after_this_request inside a teardown or before_first_request handler. Background workers spawned without copying the request context.

Related errors


AI-assisted analysis of pallets/flask@3596b1ab61 (2026-08-11). Data as JSON: /api/errors/bc8a3c7c21374fcf. Report an issue: GitHub.

Appendix: source

Thrown at src/flask/ctx.py:142

    request context, rather than during setup.

    .. code-block:: python

        @app.route("/")
        def index():
            @after_this_request
            def add_header(response):
                response.headers["X-Foo"] = "Parachute"
                return response

            return "Hello, World!"

    .. versionadded:: 0.9
    """
    ctx = _cv_app.get(None)

    if ctx is None or not ctx.has_request:
        raise RuntimeError(
            "'after_this_request' can only be used when a request"
            " context is active, such as in a view function."
        )

    ctx._after_request_functions.append(f)
    return f


F = t.TypeVar("F", bound=t.Callable[..., t.Any])


def copy_current_request_context(f: F) -> F:
    """Decorate a function to run inside the current request context. This can
    be used when starting a background task, otherwise it will not see the app
    and request objects that were active in the parent.

    .. warning::

View on GitHub (pinned to 3596b1ab61)