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
- Ensure the provider segment of the upgrade/login URL equals the credential's provider field (compare provider_matches-compatible values).
- Re-fetch the credential and read its provider before building the request.
- 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
- Never let a provider selector and a credential_id travel independently through UI state.
- Build OAuth URLs from the credential's own provider field.
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
- System credentials cannot be upgraded
- Only OAuth2 credentials can be upgraded
- Managed credentials cannot be upgraded
- Username mismatch: authenticated as a different user
- Server did not return an access token for the Google Drive p
AI-assisted analysis of Significant-Gravitas/AutoGPT@9c8bb5550f (2026-08-14).
Data as JSON: /api/errors/15125ba75501c14e.
Report an issue: GitHub.