{"id":"8a2609959f3a8ece","repo":"pallets/flask","slug":"cannot-pop-this-context-self-r-there-is-no-ac","errorCode":null,"errorMessage":"Cannot pop this context ({self!r}), there is no active context.","messagePattern":"Cannot pop this context \\((.+?)\\), there is no active context\\.","errorType":"exception","errorClass":"RuntimeError","httpStatus":null,"severity":"error","filePath":"src/flask/ctx.py","lineNumber":471,"sourceCode":"        This context must currently be the active context, otherwise a\n        :exc:`RuntimeError` is raised. In some situations, such as streaming or\n        testing, the context may have been pushed multiple times. It will only\n        trigger cleanup once it has been popped as many times as it was pushed.\n        Until then, it will remain the active context.\n\n        :param exc: An unhandled exception that was raised while the context was\n            active. Passed to teardown functions.\n\n        .. versionchanged:: 0.9\n            Added the ``exc`` argument.\n        \"\"\"\n        if self._cv_token is None:\n            raise RuntimeError(f\"Cannot pop this context ({self!r}), it is not pushed.\")\n\n        ctx = _cv_app.get(None)\n\n        if ctx is None or self._cv_token is None:\n            raise RuntimeError(\n                f\"Cannot pop this context ({self!r}), there is no active context.\"\n            )\n\n        if ctx is not self:\n            raise RuntimeError(\n                f\"Cannot pop this context ({self!r}), it is not the active\"\n                f\" context ({ctx!r}).\"\n            )\n\n        self._push_count -= 1\n\n        if self._push_count > 0:\n            return\n\n        collect_errors = _CollectErrors()\n\n        if self._request is not None:\n            with collect_errors:","sourceCodeStart":453,"sourceCodeEnd":489,"githubUrl":"https://github.com/pallets/flask/blob/6a2f545bfd8ed31e19066a299296917e034aca58/src/flask/ctx.py#L453-L489","documentation":"After confirming the context was pushed, `pop()` reads the currently active context from the `flask.app_ctx` ContextVar and raises this RuntimeError if none is set (src/flask/ctx.py:468-473). This means the context believes it is pushed (`_cv_token` set) but the ContextVar in the current execution context is empty — the push and pop are happening in different threads, greenlets, or asyncio tasks, since ContextVars are per-execution-context.","triggerScenarios":"Pushing a context in one thread/task and calling `pop()` from another (e.g. push in a test's setup thread, pop in a worker thread or an asyncio task); popping after an executor/greenlet switch where the ContextVar didn't propagate; teardown code running in a different event-loop task than the push.","commonSituations":"Async test frameworks or fixtures where setup and teardown run in different tasks; background workers that receive a context object from the spawning request and try to pop it; custom middleware doing push/pop across gevent hub switches; long-lived context objects stored globally and popped from arbitrary threads.","solutions":["Push and pop the context in the same thread/task — ideally by replacing manual management with a `with` block so entry and exit share one execution context.","For background work, create a fresh context in the worker (`with app.app_context():` or `ctx.copy()` via `copy_current_request_context`) instead of popping the parent's context.","In async code, ensure setup and teardown run in the same task, or use an async context manager wrapping both."],"exampleFix":"# before\nctx = app.app_context()\nctx.push()  # in main thread\nThread(target=ctx.pop).start()  # pops in another thread -> RuntimeError\n\n# after\ndef worker(app):\n    with app.app_context():\n        do_work()\nThread(target=worker, args=(app,)).start()","handlingStrategy":"validation","validationCode":"from flask import has_app_context\n\nif has_app_context():\n    ctx.pop()\n# else: nothing is pushed in this execution flow — skip the pop","typeGuard":"from flask import has_app_context, has_request_context\n\ndef any_context_active() -> bool:\n    return has_app_context() or has_request_context()","tryCatchPattern":"try:\n    ctx.pop()\nexcept RuntimeError:\n    # Context was already popped or belongs to another flow;\n    # indicates unbalanced push/pop — fix the lifecycle, don't swallow silently\n    logger.exception(\"unbalanced Flask context pop\")\n    raise","preventionTips":["Never call `pop()` twice on the same context; track ownership so exactly one place pops.","Use `with` blocks so Flask balances push/pop for you even when exceptions occur.","Don't pop from a different thread/task than the one that pushed — contextvars make the pushed context invisible there.","If cleanup code might run after the context is gone, guard with `has_app_context()` before popping."],"tags":["flask","python","app-context","concurrency","contextvars"],"analyzedSha":"6a2f545bfd8ed31e19066a299296917e034aca58","analyzedAt":"2026-07-31T19:13:49.921Z","schemaVersion":2}