{"record":{"id":"bd8480b16ea3b527","repo":"BerriAI/litellm","slug":"str-e-bd8480","errorCode":null,"errorMessage":"str(e)","messagePattern":"str\\(e\\)","errorType":"exception","errorClass":"AuthenticationError","httpStatus":401,"severity":"critical","filePath":"litellm/llms/github_copilot/chat/transformation.py","lineNumber":47,"sourceCode":"        self.authenticator = Authenticator()\n\n    def _get_openai_compatible_provider_info(\n        self,\n        model: str,\n        api_base: str | None,\n        api_key: str | None,\n        custom_llm_provider: str,\n    ) -> tuple[str | None, str | None, str]:\n        dynamic_api_base: Final = (\n            api_base\n            or self.authenticator.get_api_base()\n            or os.getenv(\"GITHUB_COPILOT_API_BASE\")\n            or DEFAULT_GITHUB_COPILOT_API_BASE\n        )\n        try:\n            dynamic_api_key: Final = self.authenticator.get_api_key()\n        except GetAPIKeyError as e:\n            raise AuthenticationError(\n                model=model,\n                llm_provider=custom_llm_provider,\n                message=str(e),\n            )\n        return dynamic_api_base, dynamic_api_key, custom_llm_provider\n\n    def _transform_messages(\n        self,\n        messages,\n        model: str,\n    ):\n        import litellm\n\n        # Check if system-to-assistant conversion is disabled\n        if litellm.disable_copilot_system_to_assistant:\n            # GitHub Copilot API now supports system prompts for all models (Claude, GPT, etc.)\n            # No conversion needed - just return messages as-is\n            return messages","sourceCodeStart":29,"sourceCodeEnd":65,"githubUrl":"https://github.com/BerriAI/litellm/blob/6c2dcb801bf2b75c18f1bb24140e7cf57465cc4d/litellm/llms/github_copilot/chat/transformation.py#L29-L65","documentation":"Raised in the chat transformation's validate_environment when self.authenticator.get_api_key() throws GetAPIKeyError; it is re-raised as a litellm AuthenticationError whose message is str(e) of the original (e.g. 'API key response missing token', 'Failed to refresh API key: ...', or the save-failure variant). This is a pass-through wrapper: the root cause is always one of the authenticator failures (errors 1626/1627/1628/1629/1631 upstream).","triggerScenarios":"Any litellm.completion(..., model=\"github_copilot/...\") call where the Copilot key pipeline fails: no completed device-flow login, expired/revoked access token that cannot refresh, unwritable token cache, or a refresh response missing the token field. The str(e) message identifies which sub-failure fired.","commonSituations":"First-ever use on a machine without cached Copilot credentials; headless servers where the OAuth flow was never completed; CI jobs with ephemeral home dirs losing the token cache; token cache dir made read-only in hardened container images.","solutions":["Read the embedded message: it names the real failure (refresh failed / missing token / save failed) — fix that underlying cause using the corresponding guidance.","For first-time/unauthenticated setups, complete the OAuth device flow interactively once and ship the resulting token cache to the server.","Ensure the token cache directory exists, is writable, and persists across restarts.","Upgrade litellm if the message indicates response-shape problems ('missing token'), since the authenticator tracks GitHub's internal endpoints."],"exampleFix":"# before: fresh deployment, no cached Copilot credentials\nlitellm.completion(model=\"github_copilot/gpt-4o\", messages=[{\"role\": \"user\", \"content\": \"hi\"}])\n# AuthenticationError: (missing/failed key via str(e))\n\n# after: pre-flight the authenticator before first request\nfrom litellm.llms.github_copilot.authenticator import GitHubCopilotAuthenticator\nauth = GitHubCopilotAuthenticator()\ntry:\n    auth.get_api_key()\nexcept Exception as e:\n    raise SystemExit(f\"Complete GitHub Copilot login first: {e}\")\nlitellm.completion(model=\"github_copilot/gpt-4o\", messages=[{\"role\": \"user\", \"content\": \"hi\"}])","handlingStrategy":"try-catch","validationCode":"from litellm.llms.github_copilot.authenticator import GitHubCopilotAuthenticator\n\ntry:\n    key = GitHubCopilotAuthenticator().get_api_key()\n    assert key, \"empty key returned\"\nexcept Exception as e:\n    raise SystemExit(f\"github_copilot chat unavailable — authenticate first: {e}\")","typeGuard":null,"tryCatchPattern":"from litellm.exceptions import AuthenticationError\n\ntry:\n    resp = litellm.completion(model=\"github_copilot/gpt-4o\", messages=msgs)\nexcept AuthenticationError as e:\n    # str(e) carries the root cause: refresh failed / missing token / save failed\n    if \"Failed to save API key\" in str(e):\n        fix_token_dir_permissions()  # infra fix, then retry\n    else:\n        raise SystemExit(f\"Copilot auth needs operator action: {e}\") from e","preventionTips":["Run a get_api_key() pre-flight at service startup and fail fast.","Persist the Copilot token cache across restarts (writable volume).","Classify by embedded message before retrying — only permission issues are self-healable.","Keep litellm updated for current Copilot endpoint contracts."],"tags":["github-copilot","authentication","oauth","chat","wrapper"],"backgroundTag":null,"analyzedSha":"6c2dcb801bf2b75c18f1bb24140e7cf57465cc4d","analyzedAt":"2026-08-15T07:12:03.035Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}