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"] = initiator

View on GitHub (pinned to 6c2dcb801b)

Solutions

  1. Delete the api-key.json (and access-token) cache files and re-run the device-flow login.
  2. Never hand-author the cache — always let the authenticator write it after a real OAuth flow.
  3. Validate any pre-seeded cache contains a non-empty token before deploying (jq '.token | length > 0').
  4. 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

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

Related errors


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