{"record":{"id":"a621d940e83f8c73","repo":"PrefectHQ/fastmcp","slug":"task-group-is-not-initialized-make-sure-to-use-ru","errorCode":null,"errorMessage":"Task group is not initialized. Make sure to use run().","messagePattern":"Task group is not initialized\\. Make sure to use run\\(\\)\\.","errorType":"exception","errorClass":"RuntimeError","httpStatus":null,"severity":"critical","filePath":"fastmcp_slim/fastmcp/server/http.py","lineNumber":89,"sourceCode":"        # The SDK reads `self.event_store` once when constructing each transport.\n        # A fresh adapter gives that transport a private stream namespace.\n        return SessionScopedEventStore(self._shared_event_store, session_id=uuid4().hex)\n\n    @event_store.setter\n    def event_store(self, event_store: EventStore | None) -> None:\n        self._shared_event_store = event_store\n\n\nclass StreamableHTTPASGIApp:\n    \"\"\"ASGI application wrapper for Streamable HTTP server transport.\"\"\"\n\n    def __init__(self, session_manager: StreamableHTTPSessionManager | None):\n        self.session_manager = session_manager\n\n    async def __call__(self, scope: Scope, receive: Receive, send: Send) -> None:\n        try:\n            if self.session_manager is None:\n                raise RuntimeError(\n                    \"Task group is not initialized. Make sure to use run().\"\n                )\n            await self.session_manager.handle_request(scope, receive, send)\n        except RuntimeError as e:\n            if str(e) == \"Task group is not initialized. Make sure to use run().\":\n                logger.error(\n                    f\"Original RuntimeError from mcp library: {e}\", exc_info=True\n                )\n                new_error_message = (\n                    \"FastMCP's StreamableHTTPSessionManager task group was not initialized. \"\n                    \"This commonly occurs when the FastMCP application's lifespan is not \"\n                    \"passed to the parent ASGI application (e.g., FastAPI or Starlette). \"\n                    \"Please ensure you are setting `lifespan=mcp_app.lifespan` in your \"\n                    \"parent app's constructor, where `mcp_app` is the application instance \"\n                    \"returned by `fastmcp_instance.http_app()`. \\\\n\"\n                    \"For more details, see the FastMCP ASGI integration documentation: \"\n                    \"https://gofastmcp.com/deployment/asgi\"\n                )","sourceCodeStart":71,"sourceCodeEnd":107,"githubUrl":"https://github.com/PrefectHQ/fastmcp/blob/1f021142978e0861cd910c8df4e8074bc7cf3978/fastmcp_slim/fastmcp/server/http.py#L71-L107","documentation":"The StreamableHTTP ASGI wrapper requires its StreamableHTTPSessionManager to have been started via run(), which initializes the underlying anyio task group. If session_manager is None (run() never called) the ASGI app raises RuntimeError 'Task group is not initialized. Make sure to use run().' and logs it as an internal server error.","triggerScenarios":"Mounting the http_app/ASGI callable in a server (uvicorn, starlette) without awaiting the lifespan that calls session_manager.run(); running the ASGI app outside its lifespan context; constructing the wrapper manually without a manager.","commonSituations":"Deploying with gunicorn without lifespan support (or lifespan='off'); mounting the FastMCP http_app in an existing Starlette app without including its lifespan; calling the ASGI app in tests without a lifespan context.","solutions":["Run the app through its lifespan: use fastmcp http_app() with a server that supports lifespan (uvicorn app, not just the raw ASGI callable).","In a custom Starlette app, use its .router/lifespan context so FastMCP's lifespan (which calls session_manager.run()) executes before requests.","Enable lifespan in the deployment (e.g. remove lifespan='off' from uvicorn/gunicorn config).","In tests, wrap requests in the app's lifespan context (e.g. asgi_lifespan.LifespanManager)."],"exampleFix":"// before\nuvicorn config: gunicorn -k uvicorn.workers.UvicornWorker app:asgi_app --no-lifespan\n// after\n# let lifespan run so session_manager.run() initializes the task group\ngunicorn -k uvicorn.workers.UvicornWorker app:asgi_app  # lifespan enabled","handlingStrategy":"validation","validationCode":"# ensure lifespan ran before serving\nfrom contextlib import asynccontextmanager\n@asynccontextmanager\nasync def lifespan(app):\n    async with fastmcp_app.lifespan(fastmcp_app):\n        yield","typeGuard":"def session_manager_running(app) -> bool:\n    mgr = getattr(app.state, \"session_manager\", None)\n    return mgr is not None and getattr(mgr, \"_task_group\", None) is not None","tryCatchPattern":"try:\n    await app(scope, receive, send)\nexcept RuntimeError as e:\n    if \"Task group is not initialized\" in str(e):\n        logger.error(\"Serve via fastmcp http_app() with lifespan enabled\")\n    raise","preventionTips":["Never disable lifespan in uvicorn/gunicorn when serving FastMCP http apps","Include the FastMCP lifespan when mounting into a custom Starlette app","Use asgi_lifespan.LifespanManager in tests around the ASGI app"],"tags":["asgi","lifespan","deployment"],"backgroundTag":"task-group-not-initialized","analyzedSha":"1f021142978e0861cd910c8df4e8074bc7cf3978","analyzedAt":"2026-08-29T14:31:16.082Z","schemaVersion":2},"datasetVersion":"2026-08-29T17:17:51.833Z"}