pallets/flask · error · RuntimeError

Cannot pop this context ({self!r}), it is not pushed.

Error message

Cannot pop this context ({self!r}), it is not pushed.

What it means

`AppContext.pop` requires the context to have been pushed: `push()` stores a ContextVar token in `_cv_token`, and `pop()` raises this RuntimeError when `_cv_token is None` (src/flask/ctx.py:465-466). It exists to catch unbalanced context management — popping a context that was never pushed, or popping it more times than it was pushed (contexts are re-entrant and count pushes).

Source

Thrown at src/flask/ctx.py:466

        call teardown functions and signals.

        Typically, this is not used directly. Instead, use a ``with`` block
        to manage the context.

        This context must currently be the active context, otherwise a
        :exc:`RuntimeError` is raised. In some situations, such as streaming or
        testing, the context may have been pushed multiple times. It will only
        trigger cleanup once it has been popped as many times as it was pushed.
        Until then, it will remain the active context.

        :param exc: An unhandled exception that was raised while the context was
            active. Passed to teardown functions.

        .. versionchanged:: 0.9
            Added the ``exc`` argument.
        """
        if self._cv_token is None:
            raise RuntimeError(f"Cannot pop this context ({self!r}), it is not pushed.")

        ctx = _cv_app.get(None)

        if ctx is None or self._cv_token is None:
            raise RuntimeError(
                f"Cannot pop this context ({self!r}), there is no active context."
            )

        if ctx is not self:
            raise RuntimeError(
                f"Cannot pop this context ({self!r}), it is not the active"
                f" context ({ctx!r})."
            )

        self._push_count -= 1

        if self._push_count > 0:
            return

View on GitHub ↗ (pinned to 6a2f545bfd)

Solutions

  1. Prefer `with app.app_context():` / `with app.test_request_context():` and remove all manual push/pop calls for that context.
  2. If manual management is required, pair every `pop()` with exactly one `push()` in try/finally: `ctx.push(); try: ... finally: ctx.pop()`.
  3. Audit tests for fixtures that both use a `with` block and call `ctx.pop()` in teardown — delete the redundant pop.

Example fix

# before
ctx = app.app_context()
do_work()
ctx.pop()  # never pushed -> RuntimeError

# after
with app.app_context():
    do_work()
Defensive patterns

Strategy: validation

Validate before calling

# Use the context manager so push/pop always pair correctly:
with app.app_context():
    do_work()
# instead of manual ctx.push() ... ctx.pop() across code paths

Type guard

def is_current_context(ctx) -> bool:
    """True if ctx is the innermost pushed app context."""
    from flask.globals import app_ctx
    return app_ctx._get_current_object() is ctx if app_ctx else False

Try / catch

ctx = app.app_context()
ctx.push()
try:
    do_work()
finally:
    ctx.pop()  # pop exactly what you pushed, in the same scope

Prevention

When it happens

Trigger: Calling `ctx.pop()` on a context created with `app.app_context()`/`app.test_request_context()` without a prior `ctx.push()`; calling `pop()` twice after a single `push()`; mixing manual `push()`/`pop()` with a `with` block on the same context object (the `with` exit pops, then your manual `pop()` fails).

Common situations: Test setups doing manual `ctx = app.app_context(); ...; ctx.pop()` where the `push()` was lost in a refactor or an exception skipped it; teardown fixtures popping a context that a `with` block already closed; double-pop in try/finally plus context-manager patterns; misuse of `app.test_client()` internals in custom test harnesses.

Related errors


AI-assisted analysis of pallets/flask@6a2f545bfd (2026-07-31). Data as JSON: /data/errors/0918783234736171.json. Report an issue: GitHub ↗.