PrefectHQ/fastmcp · error · RuntimeError
session_id is not available because no session exists. This
Error message
session_id is not available because no session exists. This typically means you're outside a request context.
What it means
Context.session_id resolves the stable per-client session identity. If no session exists — you are outside a request context and no background-task session ID was stashed in _background_task_session_id — the property raises RuntimeError. This typically means the code is not running inside any MCP request.
Source
Thrown at fastmcp_slim/fastmcp/server/context.py:750
from uuid import uuid4
# Get session from request context or _session (for on_initialize)
request_ctx = self.request_context
if request_ctx is not None:
session = request_ctx.session
elif self._session is not None:
session = self._session
else:
# Background task: no live session, but the submitting request's
# stable session id was captured in the task snapshot. Use it so
# session-scoped state (session_id / get_state / set_state) keeps
# working in a worker, keyed to the same client that submitted.
from fastmcp.server.dependencies import _background_task_session_id
task_session_id = _background_task_session_id.get()
if task_session_id is not None:
return task_session_id
raise RuntimeError(
"session_id is not available because no session exists. "
"This typically means you're outside a request context."
)
# In SDK v2 the ServerSession is constructed fresh per request, so the
# stable per-client identity lives on the underlying Connection, which
# persists for the whole client session. Cache the state prefix on the
# connection (its `session_id` for HTTP, its `state` dict otherwise) so
# session-scoped state survives across tool calls.
connection = getattr(session, "_connection", None)
# Check for a cached prefix on the stable connection (or the session, as
# a fallback for on_initialize where only a raw session is available).
if connection is not None:
cached = connection.state.get("_fastmcp_state_prefix")
if cached is not None:
return cached
session_cached = getattr(session, "_fastmcp_state_prefix", None)View on GitHub (pinned to 1f02114297)
Solutions
- Only access session_id inside a live request context.
- For background work, submit tasks through FastMCP's background-task mechanism, which sets _background_task_session_id from the submitting client.
- Capture session_id in the request and pass it explicitly to deferred code.
- Guard with a None check on the underlying session/request_context before reading the property.
Example fix
// before
async def tool(ctx: Context):
asyncio.create_task(worker(ctx)) # session_id lost
// after
async def tool(ctx: Context):
sid = ctx.session_id # capture inside the request
asyncio.create_task(worker(sid)) Defensive patterns
Strategy: validation
Validate before calling
sid = ctx.session_id if ctx.request_context is not None else None
if sid is None:
sid = "no-session" Type guard
def has_session(ctx) -> bool:
try:
return ctx.request_context is not None
except Exception:
return False Try / catch
try:
sid = ctx.session_id
except RuntimeError:
sid = None # outside a request context Prevention
- Use FastMCP's background-task mechanism so _background_task_session_id propagates to workers.
- Capture session_id inside the request and pass it explicitly to deferred code.
- Never access ctx.session_id from startup hooks, scheduled jobs, or bare Context instances.
When it happens
Trigger: Accessing ctx.session_id outside a request (startup hooks, standalone scripts, tests), or in a background/worker task that did not propagate the session ID via the _background_task_session_id contextvar.
Common situations: Scheduled jobs calling tools directly; test harnesses constructing Context objects; worker pools executing tool logic detached from the submitting request without the background-task session propagation FastMCP provides.
Related errors
- session is not available because the MCP session has not bee
- FastMCP instance is no longer available
- Unexpected CreateTaskResult: Context calls should not have t
- request_id is not available because the MCP session has not
- Imperative ctx.elicit() is not supported inside a background
AI-assisted analysis of PrefectHQ/fastmcp@1f02114297 (2026-08-29).
Data as JSON: /api/errors/216ed41390202533.
Report an issue: GitHub.