{"record":{"id":"37646ddd81e566c8","repo":"BerriAI/litellm","slug":"could-not-resolve-credentials-token-got-none-or-n","errorCode":null,"errorMessage":"Could not resolve credentials token. Got None or non-string token (type={type(_credentials.token).__name__})","messagePattern":"Could not resolve credentials token\\. Got None or non-string token \\(type=(.+?)\\)","errorType":"exception","errorClass":"ValueError","httpStatus":null,"severity":"critical","filePath":"litellm/llms/vertex_ai/vertex_llm_base.py","lineNumber":832,"sourceCode":"                credentials=credentials,\n                project_id=project_id,\n                credential_cache_key=credential_cache_key,\n            )\n            if project_id is None and isinstance(credential_project_id, str):\n                project_id = credential_project_id\n                cache_credentials: Final = json.dumps(credentials) if isinstance(credentials, dict) else credentials\n                resolved_cache_key: Final = (cache_credentials, project_id)\n                # Always overwrite — any pre-existing entry at the resolved key\n                # references the OLD credentials object we just replaced, and\n                # leaving it would force the next request to do a redundant\n                # refresh/reauth before realizing the cached creds are stale.\n                self._credentials_project_mapping[resolved_cache_key] = (\n                    _credentials,\n                    credential_project_id,\n                )\n\n            if _credentials.token is None or not isinstance(_credentials.token, str):\n                raise ValueError(\n                    f\"Could not resolve credentials token. Got None or non-string token (type={type(_credentials.token).__name__})\"\n                )\n            if project_id is None:\n                raise ValueError(\"Could not resolve project_id\")\n\n            return _credentials.token, project_id\n        except Exception as retry_error:\n            verbose_logger.error(\n                \"Async reauthentication retry failed for project_id: %s. Original error: %s. Retry error: %s\",\n                project_id,\n                error,\n                retry_error,\n            )\n            raise error\n\n    def get_access_token(\n        self,\n        credentials: VERTEX_CREDENTIALS_TYPES | None,","sourceCodeStart":814,"sourceCodeEnd":850,"githubUrl":"https://github.com/BerriAI/litellm/blob/77b7c6c40c0c5aa5fbcb1d6a1825ac39ca8829b8/litellm/llms/vertex_ai/vertex_llm_base.py#L814-L850","documentation":"This ValueError comes from `_handle_reauthentication_async`, the async retry path that reloads Google credentials after a \"Reauthentication is needed\" failure. After re-loading and refreshing credentials, the code validates that `_credentials.token` is a non-None string; a None or non-string token means the refreshed google-auth credentials object still cannot produce a usable OAuth bearer token. It indicates the credential source itself is broken (e.g. malformed service-account JSON, deleted key, or an auth library that returned no token), not just an expired token.","triggerScenarios":"Long-running async workloads using Vertex AI where the cached credentials expired, the refresh raised \"Reauthentication is needed\", the cache was cleared, `load_auth` re-ran, but the resulting credentials object has `token is None` (never computed) or a non-string token; typical with externally-supplied credentials strings that are invalid JSON or reference a revoked private key.","commonSituations":"A corrupted or truncated GOOGLE_APPLICATION_CREDENTIALS file; a service-account key deleted in GCP console while the process was running; impersonated credentials whose source credential expired; mixing `vertex_credentials` strings that are dicts/paths rather than serialized JSON.","solutions":["Regenerate the service-account key and update the credentials file/env var (VERTEXAI_CREDENTIALS or GOOGLE_APPLICATION_CREDENTIALS), then restart the process.","Validate the credentials file parses and the key exists: run `gcloud auth application-default login` or `gcloud iam service-accounts keys create` to produce a fresh key.","Run `gcloud auth application-default print-access-token` in the same environment to confirm the ADC chain can mint a token.","If passing `vertex_credentials` as a string, ensure it is the full JSON contents of the key file, not a file path."],"exampleFix":null,"handlingStrategy":"retry","validationCode":"from google.oauth2 import service_account\nfrom google.auth.transport.requests import Request\n\ndef creds_can_mint_token(creds) -> bool:\n    try:\n        creds.refresh(Request())\n        return isinstance(creds.token, str) and len(creds.token) > 0\n    except Exception:\n        return False","typeGuard":null,"tryCatchPattern":"try:\n    resp = await litellm.acompletion(model=\"vertex_ai/gemini-1.5-pro\", messages=msgs)\nexcept ValueError as e:\n    if \"Could not resolve credentials token\" in str(e):\n        # credential source is broken: refresh the source, then retry once\n        reload_credentials_from_secret_store()\n        resp = await litellm.acompletion(model=\"vertex_ai/gemini-1.5-pro\", messages=msgs)\n    else:\n        raise","preventionTips":["Load service-account JSON fresh from your secret store at startup and pass it via vertex_credentials instead of relying on a long-lived local file.","Monitor for 'Reauthentication is needed' log lines and treat them as a signal to rotate credentials.","Run a token-refresh smoke test (creds.refresh(Request()); assert isinstance(creds.token, str)) in your healthcheck."],"tags":["vertex-ai","google-auth","credentials","token-refresh","async"],"backgroundTag":"gcp-credentials-refresh-failed","analyzedSha":"77b7c6c40c0c5aa5fbcb1d6a1825ac39ca8829b8","analyzedAt":"2026-08-18T11:44:31.656Z","schemaVersion":2},"datasetVersion":"2026-08-27T08:17:20.692Z"}