BerriAI/litellm · critical · GetAPIKeyError
Failed to refresh API key: {e}
Error message
Failed to refresh API key: {e} What it means
Raised in get_api_key() when the underlying token refresh (_refresh_api_key) exhausts its own retry loop and throws RefreshAPIKeyError, which is then wrapped as GetAPIKeyError(401). The inner message (from the original failure — HTTP errors or unexpected exceptions during refresh) is chained into this message. Practically this means the cached Copilot access token can no longer be exchanged for a Copilot session API key.
Source
Thrown at litellm/llms/github_copilot/authenticator.py:126
api_key_info = self._refresh_api_key()
with open(self.api_key_file, "w") as f:
json.dump(api_key_info, f)
token: Final = api_key_info.get("token")
if token:
return token
else:
raise GetAPIKeyError(
message="API key response missing token",
status_code=401,
)
except OSError as e:
verbose_logger.error("Error saving API key to file: %s", e)
raise GetAPIKeyError(
message=f"Failed to save API key: {e}",
status_code=500,
)
except RefreshAPIKeyError as e:
raise GetAPIKeyError(
message=f"Failed to refresh API key: {e}",
status_code=401,
)
def get_api_base(self) -> str | None:
"""
Get the API endpoint from the api-key.json file.
Returns:
Optional[str]: The GitHub Copilot API endpoint, or None if not found.
"""
try:
with open(self.api_key_file, "r") as f:
api_key_info: Final = json.load(f)
endpoints: Final = api_key_info.get("endpoints", {})
api_endpoint: Final = endpoints.get("api")
return api_endpoint
except (OSError, json.JSONDecodeError, KeyError) as e:View on GitHub (pinned to 6c2dcb801b)
Solutions
- Re-run the device-flow login to obtain a fresh access token (delete cached token files, then authenticate interactively once).
- Confirm your GitHub account still has an active Copilot subscription/seat and the OAuth grant was not revoked (GitHub Settings -> Applications).
- Check verbose logs for the per-attempt refresh errors — 401 means dead access token, 403/429 means rate limits or entitlement loss.
- Upgrade litellm: the Copilot authenticator's endpoints and required headers (editor-version etc.) have changed across releases.
Example fix
# before: expired cached access token -> RefreshAPIKeyError -> GetAPIKeyError(401) on every call
import litellm
litellm.completion(model="github_copilot/claude-sonnet-4", messages=[...])
# after: clear cache and re-auth via device flow, then resume
import shutil, pathlib
cache = pathlib.Path("~/.litellm/github_copilot").expanduser()
if cache.exists(): shutil.rmtree(cache)
# run `litellm --login github_copilot` once, verify at github.com/login/device
litellm.completion(model="github_copilot/claude-sonnet-4", messages=[...]) Defensive patterns
Strategy: fallback
Validate before calling
import json, pathlib, time
info_path = pathlib.Path("~/.litellm/github_copilot/api-key.json").expanduser()
if info_path.exists():
info = json.loads(info_path.read_text())
expires = info.get("expires_at", 0)
if expires and time.time() > expires - 300:
print("warning: Copilot api-key near/past expiry — expect refresh; ensure access token is still valid") Try / catch
from litellm.exceptions import AuthenticationError
try:
resp = litellm.completion(model="github_copilot/gpt-4o", messages=msgs)
except AuthenticationError as e:
if "Failed to refresh API key" in str(e):
# access token dead past refresh window — only cure is re-login
raise SystemExit("Copilot session expired; re-run 'litellm --login github_copilot' to re-authenticate") from e
raise Prevention
- Schedule a periodic interactive re-auth (or scripted device flow) before the access token's refresh window lapses.
- Alert when refresh failures repeat — proactive re-login beats headless failure.
- Keep exactly one litellm version owning the token cache dir.
- Verify the GitHub account retains its Copilot entitlement after org changes.
When it happens
Trigger: The Copilot token endpoint rejects the stored access token on every retry attempt: access token expired past its refresh window (cached creds too old), GitHub revoked the OAuth grant, or the refresh HTTP call fails 3 times (5xx/rate-limit/network). Each underlying error is logged via verbose_logger.error before the wrapper raises.
Common situations: Long-lived deployments whose cached access token expired and cannot refresh (GitHub access tokens for Copilot internal flow are short-lived); users revoking the GitHub Copilot app authorization; sustained GitHub API rate limiting from too many refresh calls; litellm version drift where the refresh endpoint/headers changed (editor version headers matter).
Related errors
- Failed to get access token after 3 attempts
- Failed to refresh API key after maximum retries
- API key response missing token
- str(e)
- GitHub Copilot API key is required. Please authenticate via
AI-assisted analysis of BerriAI/litellm@6c2dcb801b (2026-08-15).
Data as JSON: /api/errors/0e2c9cce71770618.
Report an issue: GitHub.