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 Copilot embedding transformation's validate_environment when the OAuth-obtained API key is falsy after get_api_key() returns (None or empty string). This branch is defensive: get_api_key() normally raises on failure rather than returning empty, so hitting this means the authenticator returned an empty value without error — e.g. a hand-placed api-key.json whose 'token' is an empty string. The message directs you to the OAuth Device Flow.

Source

Thrown at litellm/llms/github_copilot/embedding/transformation.py:66

    def validate_environment(
        self,
        headers: dict,
        model: str,
        messages: list,
        optional_params: dict,
        litellm_params: dict,
        api_key: str | None = None,
        api_base: str | None = None,
    ) -> dict:
        """
        Validate environment and set up headers for GitHub Copilot API.
        """
        try:
            # Get GitHub Copilot API key via OAuth
            api_key = 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
            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}

            verbose_logger.debug("GitHub Copilot Embedding API: Successfully configured headers for model %s", model)

            return merged_headers

        except GetAPIKeyError as e:
            raise AuthenticationError(
                model=model,

View on GitHub (pinned to 6c2dcb801b)

Solutions

  1. Delete the corrupted api-key.json cache and let the authenticator refresh/re-authenticate from scratch.
  2. Complete the GitHub Copilot OAuth device flow (litellm --login github_copilot, then verify at github.com/login/device).
  3. If injecting a pre-baked token cache in deployments, validate it contains a non-empty 'token' before shipping.
  4. Re-run the embedding call after the cache is repopulated.

Example fix

# before: hand-crafted cache with empty token
# ~/.litellm/github_copilot/api-key.json: {"token": "", "expires_at": 0}
litellm.embedding(model="github_copilot/text-embedding-3-small", input=["hello"])

# after: remove the broken cache; authenticate via device flow so token is real
import pathlib, shutil
cache = pathlib.Path("~/.litellm/github_copilot/api-key.json").expanduser()
if cache.exists(): cache.unlink()
# litellm --login github_copilot  (one-time)
litellm.embedding(model="github_copilot/text-embedding-3-small", 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():
    token = json.loads(cache.read_text()).get("token")
    if not token:
        cache.unlink()
        print("removed empty-token cache; device-flow login will re-create it")

Type guard

def copilot_cache_has_token(cache_path: pathlib.Path) -> bool:
    try:
        return bool(json.loads(cache_path.read_text()).get("token"))
    except (FileNotFoundError, json.JSONDecodeError, OSError):
        return False

Try / catch

from litellm.exceptions import AuthenticationError

try:
    emb = litellm.embedding(model="github_copilot/text-embedding-3-small", input=["hi"])
except AuthenticationError as e:
    if "authenticate via OAuth Device Flow" in str(e):
        raise SystemExit("Run 'litellm --login github_copilot' once, then retry") from e
    raise

Prevention

When it happens

Trigger: Calling litellm.embedding(..., model="github_copilot/...") when the token cache contains an api-key.json with an empty/None 'token' value, or the authenticator path returns an empty key. Any real refresh/expiry failure would raise GetAPIKeyError instead (caught separately below this check).

Common situations: Users manually creating or editing api-key.json templates and leaving token blank; secrets managers injecting an empty string as the cached token; partial writes to the cache file from a killed process.

Understand the failure class

Related errors


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