{"record":{"id":"c8adce079f382b92","repo":"BerriAI/litellm","slug":"authentication-failed-check-your-gitlab-token-and","errorCode":null,"errorMessage":"Authentication failed. Check your GitLab token and auth_method.","messagePattern":"Authentication failed\\. Check your GitLab token and auth_method\\.","errorType":"exception","errorClass":"Exception","httpStatus":401,"severity":"error","filePath":"litellm/integrations/gitlab/gitlab_client.py","lineNumber":149,"sourceCode":"\n            ctype: Final = (resp.headers.get(\"content-type\") or \"\").lower()\n            if ctype.startswith(\"text/\") or \"charset=\" in ctype or ctype.startswith(\"application/json\"):\n                return resp.text\n            try:\n                return resp.content.decode(\"utf-8\")\n            except Exception:\n                return resp.content.decode(\"utf-8\", errors=\"replace\")\n\n        except Exception as e:\n            status: Final = getattr(getattr(e, \"response\", None), \"status_code\", None)\n            if status == 404:\n                return None\n            if status == 403:\n                raise Exception(\n                    f\"Access denied to file '{file_path}'. Check your GitLab permissions for project '{self.project}'.\"\n                )\n            if status == 401:\n                raise Exception(\"Authentication failed. Check your GitLab token and auth_method.\")\n            raise Exception(f\"Failed to fetch file '{file_path}': {e}\")\n\n    def _get_file_content_via_json(self, file_path: str, *, ref: str | None = None) -> str | None:\n        \"\"\"\n        Fallback for get_file_content(): use the JSON file API which returns base64 content.\n        \"\"\"\n        json_url: Final = self._file_json_url(file_path, ref=ref)\n        try:\n            resp: Final = self.http_handler.get(json_url, headers=self.headers)\n            if resp.status_code == 404:\n                return None\n            resp.raise_for_status()\n            data: Final = resp.json()\n            content: Final = data.get(\"content\")\n            encoding: Final = data.get(\"encoding\", \"\")\n            if content and encoding == \"base64\":\n                try:\n                    return base64.b64decode(content).decode(\"utf-8\")","sourceCodeStart":131,"sourceCodeEnd":167,"githubUrl":"https://github.com/BerriAI/litellm/blob/6c2dcb801bf2b75c18f1bb24140e7cf57465cc4d/litellm/integrations/gitlab/gitlab_client.py#L131-L167","documentation":"Raised by GitLabClient._get_file_content_via_raw when the GitLab raw-file API returns HTTP 401: authentication failed — the token is missing, malformed, expired, or revoked. Headers are built in __init__ based on auth_method ('token' sends Private-Token; 'oauth' sends Authorization: Bearer).","triggerScenarios":"Expired or revoked personal access token; auth_method set to 'oauth' while supplying a PAT (PATs are not Bearer JWTs, so GitLab rejects them); token string with stray whitespace or a truncated copy-paste; project access token rotated on the server but not in litellm config.","commonSituations":"GitLab PATs expiring on their enforced schedule (admins often cap at 1 year or less); tokens rotated by a security team without updating the proxy's environment; switching between auth methods without changing the token type.","solutions":["Test the token directly: curl -H 'Private-Token: <token>' 'https://gitlab.com/api/v4/user' — 401 means the token itself is bad.","If auth_method is 'oauth', supply an OAuth/Bearer-capable token or switch auth_method to 'token' for PATs.","Regenerate/rotate the token and update the environment variable or config backing access_token, then restart the service."],"exampleFix":"# before\ngitlab_config = {\n  \"project\": \"acme/prompts\",\n  \"access_token\": \"glpat-...\",\n  \"auth_method\": \"oauth\",  # PAT is not a Bearer token -> 401\n}\n\n# after\ngitlab_config = {\n  \"project\": \"acme/prompts\",\n  \"access_token\": \"glpat-...\",\n  \"auth_method\": \"token\",\n}","handlingStrategy":"try-catch","validationCode":"import httpx\n\ndef verify_gitlab_token(base_url: str, token: str, auth_method: str = \"token\") -> None:\n    header = {\"Authorization\": f\"Bearer {token}\"} if auth_method == \"oauth\" else {\"Private-Token\": token}\n    resp = httpx.get(f\"{base_url}/user\", headers=header, timeout=10)\n    if resp.status_code == 401:\n        raise PermissionError(\"GitLab token is invalid, expired, or wrong auth_method\")","typeGuard":null,"tryCatchPattern":"try:\n    content = client.get_file_content(\"chat/greet.prompt\")\nexcept Exception as e:\n    if \"Authentication failed\" in str(e):\n        rotate_gitlab_token()  # alert + refresh from secret store\n        raise\n    raise","preventionTips":["Verify tokens with GET /user during startup health checks.","Match auth_method to token type: 'token' for PATs/deploy tokens, 'oauth' for OAuth tokens.","Set expiry reminders for PATs and automate rotation before expiry."],"tags":["gitlab","http-401","authentication","credentials"],"backgroundTag":null,"analyzedSha":"6c2dcb801bf2b75c18f1bb24140e7cf57465cc4d","analyzedAt":"2026-08-15T07:12:03.035Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}