github/copilot-sdk · error · JsonRpcError
-32603
-32603
Error message
No GitHub token provider registered for registration ID {params.registration_id!r} What it means
get_token handles a JSON-RPC request for a GitHub token but no provider was registered under the requested registration_id in the client's _github_token_providers map. The client raises JsonRpcError(-32603) (internal error) because it cannot fulfill the token request without a matching registration. This indicates a lifecycle mismatch: a token was requested for a registration the client never registered or has since removed.
Solutions
- Register the GitHub token provider under that exact registration_id before issuing token requests
- Verify the registration_id used at acquire time matches the one used at registration (exact string, no whitespace)
- Ensure the same CopilotClient instance that registered the provider handles the request
- Add logging to dump client._github_token_providers keys and compare with the requested ID
Example fix
// before
result = await handler.get_token(GitHubTokenAcquireRequest(registration_id="gh-token-1"))
// after
client.register_github_token_provider("gh-token-1", my_provider) # must precede get_token
result = await handler.get_token(GitHubTokenAcquireRequest(registration_id="gh-token-1")) Defensive patterns
Strategy: try-catch
Validate before calling
# before requesting a token
with client._github_token_providers_lock:
known = params.registration_id in client._github_token_providers
if not known:
raise LookupError(f"register provider for {params.registration_id!r} first") Try / catch
from copilot.jsonrpc import JsonRpcError
try:
result = await handler.get_token(params)
except JsonRpcError as e:
if e.code == -32603 and "No GitHub token provider registered" in str(e):
client.register_github_token_provider(params.registration_id, my_provider)
result = await handler.get_token(params)
else:
raise Prevention
- Register providers before any token acquire flow starts
- Use a constant/enum for registration IDs instead of inline strings
- Keep a single client instance per registration namespace
- Log registered IDs at registration time to ease debugging
When it happens
Trigger: Calling the GitHub token acquire flow with params.registration_id that was never passed to the register-API (or was unregistered), reusing a registration_id from a different/older client instance, or a stale server-side request arriving after the provider was removed.
Common situations: Multiple CopilotClient instances in one process where the request lands on the wrong client; restarting the client and replaying old requests; race between unregistering a provider and an in-flight token request; typo in the registration ID string.
Understand the failure class
Background: "Not found" and "does not exist" errors: why "Task not found", "No such folder", and "Can't find" fire when a lookup comes back empty — this error's family across 14 libraries.
Related errors
- Unknown GitHub token provider registration ID
- Request handler must return a JSON-serializable value, got
- -32603
- Failed to detach session
- Invalid entry '*': there is no bare wildcard. Use one or…
AI-assisted analysis of github/copilot-sdk@cd8cf15dc3 (2026-09-09).
Data as JSON: /api/errors/afb4c6c8c43d06a9.
Report an issue: GitHub.
Appendix: source
Thrown at python/copilot/client.py:761
@dataclass
class _GitHubTokenProviderRegistration:
provider: GitHubTokenProvider
session_id: str | None = None
committed: bool = False
class _GitHubTokenProviderAdapter:
"""Routes global GitHub token requests to opaque session registrations."""
def __init__(self, client: CopilotClient) -> None:
self._client = client
async def get_token(self, params: GitHubTokenAcquireRequest) -> GitHubTokenAcquireResult:
with self._client._github_token_providers_lock:
registration = self._client._github_token_providers.get(params.registration_id)
if registration is None:
raise JsonRpcError(
-32603,
"No GitHub token provider registered for registration ID "
f"{params.registration_id!r}",
)
result = registration.provider(
GitHubTokenProviderArgs(
host=params.host,
session_id=params.session_id or registration.session_id,
reason=params.reason,
)
)
if inspect.isawaitable(result):
result = await result
# The generated global-handler wrapper forwards callback results directly,
# so the public tagged dictionary is already in the expected wire shape.
return cast(GitHubTokenAcquireResult, result)
View on GitHub (pinned to cd8cf15dc3)