Significant-Gravitas/AutoGPT · warning · HTTPException

Credential provider does not match the requested provider

Error message

Credential provider does not match the requested provider

What it means

In _prepare_scope_upgrade, provider_matches(existing.provider, provider.value) compares the credential's stored provider with the provider in the upgrade request URL. If they differ (e.g. upgrading via /integrations/github/login while the credential belongs to 'todoist'), HTTP 400 'Credential provider does not match the requested provider' is raised. This prevents cross-provider scope injection — merging scopes obtained from one provider's consent into another provider's credential.

Source

Thrown at autogpt_platform/backend/backend/api/features/integrations/router.py:985

    if is_system_credential(credential_id):
        raise HTTPException(
            status_code=status.HTTP_400_BAD_REQUEST,
            detail="System credentials cannot be upgraded",
        )

    existing = await creds_manager.store.get_creds_by_id(user_id, credential_id)
    if not existing:
        raise HTTPException(
            status_code=status.HTTP_404_NOT_FOUND,
            detail="Credential to upgrade not found",
        )
    if not isinstance(existing, OAuth2Credentials):
        raise HTTPException(
            status_code=status.HTTP_400_BAD_REQUEST,
            detail="Only OAuth2 credentials can be upgraded",
        )
    if not provider_matches(existing.provider, provider.value):
        raise HTTPException(
            status_code=status.HTTP_400_BAD_REQUEST,
            detail="Credential provider does not match the requested provider",
        )
    if existing.is_managed:
        raise HTTPException(
            status_code=status.HTTP_400_BAD_REQUEST,
            detail="Managed credentials cannot be upgraded",
        )

    # Google handles scope merging via include_granted_scopes; others need
    # the union of existing + new scopes in the login URL.
    if provider != ProviderName.GOOGLE:
        requested_scopes = list(set(requested_scopes) | set(existing.scopes))

    return requested_scopes


async def _merge_or_create_credential(

View on GitHub (pinned to 9c8bb5550f)

Solutions

  1. Ensure the provider segment of the upgrade/login URL equals the credential's provider field (compare provider_matches-compatible values).
  2. Re-fetch the credential and read its provider before building the request.
  3. If the provider was renamed in an upgrade, migrate stored credentials to the new provider value.

Example fix

# before
resp = client.get(f"/integrations/{selected_provider}/login", params={"upgrade_credentials_id": cred.id})

# after: derive provider from the credential itself
resp = client.get(f"/integrations/{cred.provider}/login", params={"upgrade_credentials_id": cred.id})
Defensive patterns

Strategy: validation

Validate before calling

# Derive the route provider from the credential record itself
cred = await fetch_credential(credential_id)
assert provider_matches(cred["provider"], provider), "cross-provider upgrade request"

Prevention

When it happens

Trigger: Frontend sends the upgrade request to the wrong provider route after the user switched provider in the credential dialog; ID mix-up where a credential from provider A is submitted with provider B's login URL; aliased provider names that don't match the stored value.

Common situations: UI state bug: provider selector changed but the credential_id state retained from the previous provider; copy-pasted request templates with the wrong provider segment; providers renamed between versions so stored provider values differ from current enum values.

Related errors


AI-assisted analysis of Significant-Gravitas/AutoGPT@9c8bb5550f (2026-08-14). Data as JSON: /api/errors/15125ba75501c14e. Report an issue: GitHub.