BerriAI/litellm · critical · AuthenticationError
GitHub Copilot API key is required. Please authenticate via
Error message
GitHub Copilot API key is required. Please authenticate via OAuth Device Flow.
What it means
Raised in the responses transformation's validate_environment when get_api_key() returns a falsy value (None/'') without raising. Defensive branch mirroring error 1631 for the /responses path: a real auth failure raises GetAPIKeyError (caught separately), so this fires only when an empty key came back — typically a corrupted or hand-built api-key.json with an empty 'token'.
Source
Thrown at litellm/llms/github_copilot/responses/transformation.py:206
"""
Validate environment and set up headers for GitHub Copilot API.
Uses the Authenticator to obtain GitHub Copilot API key via OAuth Device Flow,
then configures all required headers for the Responses API.
Headers include:
- Authorization with API key
- Standard GitHub Copilot headers (editor-version, user-agent, etc.)
- X-Initiator based on input analysis
- copilot-vision-request if vision content detected
- User-provided extra_headers (merged with priority)
"""
try:
# Get GitHub Copilot API key via OAuth
api_key: Final = self.authenticator.get_api_key()
if not api_key:
raise AuthenticationError(
model=model,
llm_provider="github_copilot",
message="GitHub Copilot API key is required. Please authenticate via OAuth Device Flow.",
)
# Get default headers (from copilot-api configuration)
default_headers: Final = get_copilot_default_headers(api_key)
# Merge with existing headers (user's extra_headers take priority)
merged_headers: Final = {**default_headers, **headers}
# Analyze input to determine additional headers
input_param: Final = self._get_input_from_params(litellm_params)
# Add X-Initiator header based on input analysis
if input_param is not None:
initiator: Final = self._get_initiator(input_param)
merged_headers["X-Initiator"] = initiatorView on GitHub (pinned to 6c2dcb801b)
Solutions
- Delete the api-key.json (and access-token) cache files and re-run the device-flow login.
- Never hand-author the cache — always let the authenticator write it after a real OAuth flow.
- Validate any pre-seeded cache contains a non-empty token before deploying (jq '.token | length > 0').
- Retry the responses call once the cache is repopulated by a warmup request.
Example fix
# before: image ships placeholder cache {"token": ""}
litellm.responses(model="github_copilot/gpt-4o", input="hello")
# after: no placeholder caches; authenticate properly
import pathlib
cache = pathlib.Path("~/.litellm/github_copilot/api-key.json").expanduser()
if cache.exists() and not (__import__('json').loads(cache.read_text()).get('token')):
cache.unlink() # drop empty-token cache so the authenticator re-authenticates
# litellm --login github_copilot (one-time, completes device flow)
litellm.responses(model="github_copilot/gpt-4o", input="hello") Defensive patterns
Strategy: validation
Validate before calling
import json, pathlib
cache = pathlib.Path("~/.litellm/github_copilot/api-key.json").expanduser()
if cache.exists():
try:
ok = bool(json.loads(cache.read_text()).get("token"))
except json.JSONDecodeError:
ok = False
if not ok:
cache.unlink()
print("evicted invalid Copilot cache; next call re-authenticates") Type guard
def copilot_responses_cache_valid(cache_path: pathlib.Path) -> bool:
"""Cache must exist and carry a non-empty token string."""
try:
data = json.loads(cache_path.read_text())
except (FileNotFoundError, json.JSONDecodeError, OSError):
return False
return isinstance(data.get("token"), str) and len(data["token"]) > 0 Try / catch
from litellm.exceptions import AuthenticationError
try:
resp = litellm.responses(model="github_copilot/gpt-4o", input="hi")
except AuthenticationError as e:
if "OAuth Device Flow" in str(e):
clear_copilot_cache()
raise SystemExit("Run 'litellm --login github_copilot', then restart") from e
raise Prevention
- Reject placeholder/empty token caches in image builds (jq guard in CI).
- Only the authenticator writes cache files.
- Re-run device flow after any manual cache surgery.
- Add cache validation to deployment smoke tests.
When it happens
Trigger: Calling litellm.responses(..., model="github_copilot/...") when the token cache holds an empty-string token; e.g. templated cache files deployed with placeholder values, or a truncated cache write from a killed process leaving token empty.
Common situations: Baking token caches into container images with placeholder JSON; secrets managers syncing an empty secret into the cache; partial cache corruption after OOM kills.
Understand the failure class
- Authentication and authorization failures — expired tokens, bad credentials, and missing scopes.
Related errors
- GitHub Copilot API key is required. Please authenticate via
- str(e)
- Failed to get access token after 3 attempts
- Failed to refresh API key: {e}
- str(e)
AI-assisted analysis of BerriAI/litellm@6c2dcb801b (2026-08-15).
Data as JSON: /api/errors/139e1ef758d76f51.
Report an issue: GitHub.