{"record":{"id":"7a71d39bf9040d66","repo":"BerriAI/litellm","slug":"failed-to-save-api-key-e","errorCode":null,"errorMessage":"Failed to save API key: {e}","messagePattern":"Failed to save API key: (.+?)","errorType":"exception","errorClass":"GetAPIKeyError","httpStatus":500,"severity":"error","filePath":"litellm/llms/github_copilot/authenticator.py","lineNumber":121,"sourceCode":"            verbose_logger.warning(\"Error reading API key from file: %s\", e)\n        except APIKeyExpiredError:\n            pass  # Already logged in the try block\n\n        try:\n            api_key_info = self._refresh_api_key()\n            with open(self.api_key_file, \"w\") as f:\n                json.dump(api_key_info, f)\n            token: Final = api_key_info.get(\"token\")\n            if token:\n                return token\n            else:\n                raise GetAPIKeyError(\n                    message=\"API key response missing token\",\n                    status_code=401,\n                )\n        except OSError as e:\n            verbose_logger.error(\"Error saving API key to file: %s\", e)\n            raise GetAPIKeyError(\n                message=f\"Failed to save API key: {e}\",\n                status_code=500,\n            )\n        except RefreshAPIKeyError as e:\n            raise GetAPIKeyError(\n                message=f\"Failed to refresh API key: {e}\",\n                status_code=401,\n            )\n\n    def get_api_base(self) -> str | None:\n        \"\"\"\n        Get the API endpoint from the api-key.json file.\n\n        Returns:\n            Optional[str]: The GitHub Copilot API endpoint, or None if not found.\n        \"\"\"\n        try:\n            with open(self.api_key_file, \"r\") as f:","sourceCodeStart":103,"sourceCodeEnd":139,"githubUrl":"https://github.com/BerriAI/litellm/blob/6c2dcb801bf2b75c18f1bb24140e7cf57465cc4d/litellm/llms/github_copilot/authenticator.py#L103-L139","documentation":"Raised in get_api_key() when writing the refreshed api-key JSON to disk raises OSError — the token cache file (api_key_file) cannot be created or written. The refresh itself succeeded (the API key was obtained), but persisting it failed, so litellm aborts with GetAPIKeyError 500. The underlying OSError text (permission denied, read-only file system, disk quota, directory missing) is embedded in the message.","triggerScenarios":"The token cache directory does not exist or is not writable by the process user: container images running as non-root with a read-only or unmapped volume for the token dir; files owned by root from a previous docker run; disk full (ENOSPC); SELinux/AppArmor denying writes; path too long (ENAMETOOLONG).","commonSituations":"Docker/Kubernetes deployments where the token dir lands on a read-only layer or a volume mounted with wrong ownership (root-owned after running once as root, then as UID 1000); ephemeral CI environments with full disks; macOS/Windows permission restrictions on the home directory.","solutions":["Check the OSError detail in the message — 'Permission denied' vs 'Read-only file system' vs 'No space left on device' points to the fix.","Fix ownership/permissions of the token directory: chown -R $(id -u):$(id -g) <token_dir> && chmod -R u+rwX <token_dir>.","In containers, mount a writable volume (or emptyDir) at the token dir path and run with a consistent UID.","Free disk space if ENOSPC; note the key still worked for this request only if you catch the error and use a writable dir — otherwise every call fails here."],"exampleFix":"# before: container runs as app user, token dir owned by root -> OSError every refresh\n# docker run -v litellm-tokens:/root/.litellm/github_copilot ...  (root-owned)\n\n# after: writable mount with matching ownership\n# docker run --user 1000:1000 -v litellm-tokens:/home/app/.litellm/github_copilot ...","handlingStrategy":"validation","validationCode":"import os, pathlib\n\ntoken_dir = pathlib.Path(\"~/.litellm/github_copilot\").expanduser()\ntry:\n    token_dir.mkdir(parents=True, exist_ok=True)\n    probe = token_dir / \".write_probe\"\n    probe.write_text(\"ok\")\n    probe.unlink()\nexcept OSError as e:\n    raise RuntimeError(f\"Copilot token dir not writable ({e}); fix ownership/mount before use\") from 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    if \"Failed to save API key\" in str(e):\n        raise RuntimeError(\n            \"Token cache unwritable — fix dir ownership/permissions or mount a writable volume, then retry\"\n        ) from e\n    raise","preventionTips":["Run containers with a consistent UID and a writable volume mounted at the token dir.","Include a token-dir write probe in container health checks.","chown the token dir after any root-run maintenance to the service user.","Monitor disk space — ENOSPC manifests here first."],"tags":["github-copilot","filesystem","permissions","docker","cache","oserror"],"backgroundTag":null,"analyzedSha":"6c2dcb801bf2b75c18f1bb24140e7cf57465cc4d","analyzedAt":"2026-08-15T07:12:03.035Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}