BerriAI/litellm · critical · AuthenticationError

str(e)

Error message

str(e)

What it means

Raised in the messages (Anthropic-style) transformation when self.authenticator.get_api_key() throws GetAPIKeyError; wrapped as AuthenticationError with str(e). Same wrapper family as errors 1630/1632 but for the /v1/messages proxy path. Note this path deliberately ignores caller-supplied api_base to avoid leaking the Copilot bearer token, so the failure is purely about the OAuth key pipeline.

Source

Thrown at litellm/llms/github_copilot/messages/transformation.py:75

        api_key: str | None = None,
        api_base: str | None = None,
    ) -> tuple[dict, str | None]:
        """
        Validate environment for GitHub Copilot and add Copilot-specific headers.

        The caller-supplied ``api_base`` is intentionally ignored. Routing this
        request anywhere other than the authenticated Copilot endpoint would
        leak the Copilot bearer token to a caller-controlled URL.
        """
        # Always use the Copilot endpoint resolved from the authenticated
        # session, never the caller-supplied api_base. rstrip so a
        # tenant-specific base with a trailing slash does not yield a
        # double-slash URL once "/v1/messages" is appended downstream.
        dynamic_api_base: Final = (self.authenticator.get_api_base() or DEFAULT_GITHUB_COPILOT_API_BASE).rstrip("/")
        try:
            dynamic_api_key: Final = self.authenticator.get_api_key()
        except GetAPIKeyError as e:
            raise AuthenticationError(
                model=model,
                llm_provider="github_copilot",
                message=str(e),
            )

        # Merge Copilot headers with provided headers
        copilot_headers: Final = get_copilot_default_headers(dynamic_api_key)
        for key, value in copilot_headers.items():
            if key not in headers:
                headers[key] = value

        headers["openai-intent"] = "messages-proxy"
        headers["x-interaction-type"] = "messages-proxy"
        headers["x-github-api-version"] = _MESSAGES_PROXY_API_VERSION

        if "anthropic-version" not in headers:
            headers["anthropic-version"] = "2023-06-01"

View on GitHub (pinned to 6c2dcb801b)

Solutions

  1. Complete the OAuth device flow once on the host (litellm --login github_copilot) and persist the token cache directory.
  2. Inspect str(e) to identify the sub-failure (refresh vs save vs missing token) and apply its fix.
  3. Keep the token cache on a writable, persistent volume shared only by litellm processes of the same version.
  4. Verify the GitHub account retains a Copilot subscription when refresh persistently 401s.

Example fix

# before: messages API on unauthenticated host
litellm.anthropic_messages(model="github_copilot/claude-sonnet-4", messages=[...])
# -> AuthenticationError: Failed to refresh API key ...

# after: ensure creds exist before serving traffic (startup check)
from litellm.llms.github_copilot.authenticator import GitHubCopilotAuthenticator
try:
    GitHubCopilotAuthenticator().get_api_key()
except Exception:
    raise SystemExit("github_copilot not authenticated; run 'litellm --login github_copilot'")
litellm.anthropic_messages(model="github_copilot/claude-sonnet-4", messages=[...])
Defensive patterns

Strategy: try-catch

Validate before calling

from litellm.llms.github_copilot.authenticator import GitHubCopilotAuthenticator

auth = GitHubCopilotAuthenticator()
try:
    auth.get_api_key()
except Exception as e:
    raise SystemExit(f"Copilot messages API not ready: {e}")

Try / catch

from litellm.exceptions import AuthenticationError

try:
    resp = litellm.anthropic_messages(model="github_copilot/claude-sonnet-4", messages=msgs)
except AuthenticationError as e:
    # str(e) is the wrapped GetAPIKeyError — fix the named root cause
    if "save API key" in str(e):
        fix_token_dir_permissions()
    else:
        raise SystemExit(f"Operator action required: {e}") from e

Prevention

When it happens

Trigger: Routing Anthropic-format requests through github_copilot (model like 'github_copilot/claude-sonnet-4' via the messages API) when the device-flow login was never completed, the cached access token expired and refresh fails, or the api-key cache write fails.

Common situations: Claude-Code-style clients pointed at litellm with github_copilot as backend before OAuth setup; token cache lost on container restart; Copilot seat revoked so refresh 401s; multiple litellm versions sharing one cache dir with incompatible schemas.

Related errors


AI-assisted analysis of BerriAI/litellm@6c2dcb801b (2026-08-15). Data as JSON: /api/errors/41ce8ae07a9d0288. Report an issue: GitHub.