BerriAI/litellm · critical · ValueError

Could not resolve credentials token. Got None or non-string

Error message

Could not resolve credentials token. Got None or non-string token (type={type(_credentials.token).__name__})

What it means

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.

Source

Thrown at litellm/llms/vertex_ai/vertex_llm_base.py:832

                credentials=credentials,
                project_id=project_id,
                credential_cache_key=credential_cache_key,
            )
            if project_id is None and isinstance(credential_project_id, str):
                project_id = credential_project_id
                cache_credentials: Final = json.dumps(credentials) if isinstance(credentials, dict) else credentials
                resolved_cache_key: Final = (cache_credentials, project_id)
                # Always overwrite — any pre-existing entry at the resolved key
                # references the OLD credentials object we just replaced, and
                # leaving it would force the next request to do a redundant
                # refresh/reauth before realizing the cached creds are stale.
                self._credentials_project_mapping[resolved_cache_key] = (
                    _credentials,
                    credential_project_id,
                )

            if _credentials.token is None or not isinstance(_credentials.token, str):
                raise ValueError(
                    f"Could not resolve credentials token. Got None or non-string token (type={type(_credentials.token).__name__})"
                )
            if project_id is None:
                raise ValueError("Could not resolve project_id")

            return _credentials.token, project_id
        except Exception as retry_error:
            verbose_logger.error(
                "Async reauthentication retry failed for project_id: %s. Original error: %s. Retry error: %s",
                project_id,
                error,
                retry_error,
            )
            raise error

    def get_access_token(
        self,
        credentials: VERTEX_CREDENTIALS_TYPES | None,

View on GitHub (pinned to 77b7c6c40c)

Solutions

  1. Regenerate the service-account key and update the credentials file/env var (VERTEXAI_CREDENTIALS or GOOGLE_APPLICATION_CREDENTIALS), then restart the process.
  2. 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.
  3. Run `gcloud auth application-default print-access-token` in the same environment to confirm the ADC chain can mint a token.
  4. If passing `vertex_credentials` as a string, ensure it is the full JSON contents of the key file, not a file path.
Defensive patterns

Strategy: retry

Validate before calling

from google.oauth2 import service_account
from google.auth.transport.requests import Request

def creds_can_mint_token(creds) -> bool:
    try:
        creds.refresh(Request())
        return isinstance(creds.token, str) and len(creds.token) > 0
    except Exception:
        return False

Try / catch

try:
    resp = await litellm.acompletion(model="vertex_ai/gemini-1.5-pro", messages=msgs)
except ValueError as e:
    if "Could not resolve credentials token" in str(e):
        # credential source is broken: refresh the source, then retry once
        reload_credentials_from_secret_store()
        resp = await litellm.acompletion(model="vertex_ai/gemini-1.5-pro", messages=msgs)
    else:
        raise

Prevention

When it happens

Trigger: 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.

Common situations: 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.

Related errors


AI-assisted analysis of BerriAI/litellm@77b7c6c40c (2026-08-18). Data as JSON: /api/errors/37646ddd81e566c8. Report an issue: GitHub.