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

  1. Only access session_id inside a live request context.
  2. For background work, submit tasks through FastMCP's background-task mechanism, which sets _background_task_session_id from the submitting client.
  3. Capture session_id in the request and pass it explicitly to deferred code.
  4. 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

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


AI-assisted analysis of PrefectHQ/fastmcp@1f02114297 (2026-08-29). Data as JSON: /api/errors/216ed41390202533. Report an issue: GitHub.