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

  1. Register the GitHub token provider under that exact registration_id before issuing token requests
  2. Verify the registration_id used at acquire time matches the one used at registration (exact string, no whitespace)
  3. Ensure the same CopilotClient instance that registered the provider handles the request
  4. 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

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


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)