github/copilot-sdk · error · ValueError
unknown session
Error message
unknown session {params.session_id} What it means
The hook dispatcher's invoke looks up the session by params.session_id via the provided getter; if no session matches, it raises ValueError('unknown session ...'). Hooks are routed to a specific session, so an unknown ID means the hook request cannot be delivered and processing stops.
Solutions
- Confirm the session_id exists (client.get_session / session map) before sending or processing hooks
- Recreate the session if it was stopped, and re-send the request with the new session_id
- Guard against closing sessions while hooks are pending; check session lifecycle ordering in your code
- Log the valid session IDs at failure time to spot stale IDs
Example fix
// before
session = client.get_session(session_id)
session.stop() # session removed while hooks may still arrive
// after
session = client.get_session(session_id)
# drain/ignore pending hooks first, then stop
if not has_pending_hooks(session_id):
session.stop() Defensive patterns
Strategy: try-catch
Validate before calling
if client.get_session(params.session_id) is None:
raise LookupError(f"session {params.session_id} not found; skip hook") Try / catch
try:
output = await hook_handler.invoke(params)
except ValueError as e:
if str(e).startswith("unknown session"):
logger.warning("dropping hook for stale session %s", params.session_id)
else:
raise Prevention
- Track session lifecycles and drop pending hooks on session close
- Never cache session IDs across client restarts
- Validate session_id against the live session map before dispatching hooks
When it happens
Trigger: A hook invoke request arrives with a session_id that was never created, or the session was already closed/removed from the client's session map before the hook fired.
Common situations: Client restart or session timeout between agent event and hook delivery; reusing a session ID string from a previous run; concurrent code closing a session while hooks are still in flight; copying a session_id with extra characters.
Understand the failure class
Background: Record Not Found Errors: "not found", RecordNotFound, and "was not found" — what they mean and how to fix them — this error's family across 28 libraries.
Related errors
- Failed to detach session
- Invalid entry '*': there is no bare wildcard. Use one or…
- Client is not connected. Call start() first.
- telemetry is not supported with…
- Set environment variables via either the client-level env…
AI-assisted analysis of github/copilot-sdk@cd8cf15dc3 (2026-09-09).
Data as JSON: /api/errors/ea4498c2f54c77b3.
Report an issue: GitHub.
Appendix: source
Thrown at python/copilot/client.py:795
# so the public tagged dictionary is already in the expected wire shape.
return cast(GitHubTokenAcquireResult, result)
class _HooksAdapter:
"""Adapts session-scoped hook dispatch to the generated ``HooksHandler`` protocol.
``hooks.invoke`` is a client-global RPC method whose payload carries a
``sessionId``. This adapter routes each invocation to the matching session's
registered hook handlers.
"""
def __init__(self, get_session: Callable[[str], CopilotSession | None]) -> None:
self._get_session = get_session
async def invoke(self, params: _HookInvokeRequest) -> _HookInvokeResponse:
session = self._get_session(params.session_id)
if session is None:
raise ValueError(f"unknown session {params.session_id}")
output = await session._handle_hooks_invoke(params.hook_type.value, params.input)
return _HookInvokeResponse(output=output)
@dataclass
class _CopilotClientOptions:
"""Internal configuration carrier used by :class:`CopilotClient`.
This is not part of the public API: ``CopilotClient`` accepts all of
these options as keyword arguments directly.
"""
connection: RuntimeConnection | None = None
working_directory: str | None = None
log_level: LogLevel = "info"
env: dict[str, str] | None = None
github_token: str | None = None
base_directory: str | None = NoneView on GitHub (pinned to cd8cf15dc3)