Skip to content

ClaudeSDKClient Cannot Be Shared Across Async Runtime Contexts #925

@shivansh052k

Description

@shivansh052k

Bug: ClaudeSDKClient Cannot Be Shared Across Async Runtime Contexts

Affected version: v0.0.20+
File: src/claude_agent_sdk/client.py, line 55


Description

ClaudeSDKClient instances are currently tied to the async context in which they were connected. Once connect() is called, the client spawns a persistent internal anyio task group responsible for reading incoming messages. This task group lives for the entire lifetime of the connection — from connect() through disconnect() — and cannot be safely accessed or reused from a different async runtime context.

This means the client cannot be passed to, or reused across:

  • Different trio nurseries
  • Different asyncio task groups
  • Any other concurrent async scope that was not the original caller of connect()

Why This Is a Problem

This constraint makes it difficult to build real-world applications where a single connected client needs to be shared or handed off between independent async workers, background tasks, or structured concurrency scopes. Common use cases that break under this limitation include:

  • Connecting once at startup and reusing the client in multiple task groups
  • Delegating work to a worker pool where individual tasks weren't the ones that called connect()
  • Using the client inside frameworks that manage their own async lifecycles (e.g., FastAPI, Starlette, or Hypercorn with Trio)

Expected Behavior

A connected ClaudeSDKClient instance should be usable from any async context, not just the one in which it was originally connected. The internal message-reading task group should either:

  1. Be scoped independently of any caller-owned nursery/task group, or
  2. Support safe cross-context handoff via a well-defined mechanism

Suggested Fix

Consider running the internal anyio task group in a dedicated background thread or a standalone top-level task scope that is not a child of the caller's nursery. This would decouple the client's lifetime from the async scope of the connecting caller.


References

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't workingduplicateThis issue or pull request already exists

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions