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
- Complete the OAuth device flow once on the host (litellm --login github_copilot) and persist the token cache directory.
- Inspect str(e) to identify the sub-failure (refresh vs save vs missing token) and apply its fix.
- Keep the token cache on a writable, persistent volume shared only by litellm processes of the same version.
- 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
- Authenticate once per host and persist the token cache before enabling the messages proxy.
- Never pass caller-controlled api_base on this path — it is ignored by design to protect the bearer token.
- Add get_api_key() to the readiness probe of any service fronting the messages path.
- Classify embedded causes before retrying; refresh failures need re-login.
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.