BerriAI/litellm · error · ValueError

Existing credential for user {user_id} and server {server_id

Error message

Existing credential for user {user_id} and server {server_id} could not be verified as an OAuth2 token. Refusing to overwrite.

What it means

Raised by the MCP credential store when saving an OAuth token over an existing user credential that does not decode as an OAuth2 payload (i.e. a BYOK API key). It refuses the overwrite to avoid silently destroying a user-entered key; the skip guard exists for known-refresh paths.

Source

Thrown at litellm/proxy/_experimental/mcp_server/db.py:1423

    }
    if refresh_token:
        payload["refresh_token"] = refresh_token
    if expires_at:
        payload["expires_at"] = expires_at
    if scopes:
        payload["scopes"] = scopes

    # Guard against silently overwriting a BYOK credential with an OAuth token.
    # Skip the guard when the caller knows the row is already an OAuth2 credential
    # (e.g. during token refresh), saving an extra DB round-trip.
    if not skip_byok_guard:
        existing: Final = await _db_find_user_credential_row(prisma_client, user_id, server_id)
        if existing is not None and _decode_oauth_payload(existing.credential_b64) is None:
            # Existing row is either a BYOK secret or an OAuth2 row that no
            # longer decrypts (e.g. after a salt-key rotation).  In either
            # case, refuse to overwrite — the caller would clobber data
            # that may still be recoverable.
            raise ValueError(
                f"Existing credential for user {user_id} and server "
                f"{server_id} could not be verified as an OAuth2 token. "
                f"Refusing to overwrite."
            )

    encoded: Final = encrypt_value_helper(json.dumps(payload))
    await _db_upsert_user_credential_row(prisma_client, user_id, server_id, encoded)


def is_oauth_credential_expired(cred: OAuthCredentialPayload, buffer_seconds: int = 0) -> bool:
    """Return True if the OAuth2 credential's access_token has expired.

    Checks the ``expires_at`` ISO-format string stored in the credential payload.
    Returns False when ``expires_at`` is absent or unparseable (treat as non-expired).
    With ``buffer_seconds`` > 0, a token that is still valid but expires within the
    buffer is also treated as expired, so callers can refresh proactively instead of
    handing back a token that may lapse mid-request.
    """

View on GitHub (pinned to 77b7c6c40c)

Solutions

  1. Delete the existing stored credential for that user/server, then re-run the OAuth flow.
  2. Or verify/fix the stored token so it parses as OAuth2.

Example fix

Remove the stale credential row, then re-authorize.
Defensive patterns

Strategy: validation

When it happens

Trigger: Thrown at litellm/proxy/_experimental/mcp_server/db.py:1423 when the library encounters an invalid state.

Common situations: See trigger scenarios.


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