Significant-Gravitas/AutoGPT · warning · HTTPException
Only OAuth2 credentials can be upgraded
Error message
Only OAuth2 credentials can be upgraded
What it means
In _prepare_scope_upgrade, if the existing credential resolves but is not an OAuth2Credentials instance (e.g. it's an APIKeyCredentials or UserPasswordCredentials), HTTP 400 'Only OAuth2 credentials can be upgraded' is raised. Scope upgrade is an OAuth concept: it re-runs the authorization flow requesting more scopes, which has no meaning for API-key or user/password credentials.
Source
Thrown at autogpt_platform/backend/backend/api/features/integrations/router.py:980
Raises HTTPException on validation failure.
"""
# Platform-owned system credentials must never be upgraded — scope
# changes here would leak across every user that shares them.
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))View on GitHub (pinned to 9c8bb5550f)
Solutions
- Check the credential type before offering upgrade — only credentials with type 'oauth2' are eligible.
- For API-key credentials, request additional access by getting a new key from the provider with the needed permissions and updating the stored secret — there is no scope-upgrade flow.
- In the UI, hide/disable 'upgrade scopes' actions for non-OAuth credential types.
Example fix
# before: offering upgrade for any credential
if cred.provider == provider:
show_upgrade_button(cred)
# after: only OAuth2 credentials
if cred.provider == provider and cred.type == "oauth2":
show_upgrade_button(cred) Defensive patterns
Strategy: type-guard
Type guard
def is_oauth2(cred: dict) -> bool:
return cred.get("type") == "oauth2" Prevention
- Gate 'upgrade scopes' UI on credential type == oauth2.
- For API-key credentials, plan for re-issuing the key instead of scope upgrade.
When it happens
Trigger: User selects a provider that supports both API-key and OAuth (e.g. a provider with a simple API key connection) and initiates 'upgrade scopes' against the API-key credential; request built with a credential_id that happens to belong to an API-key entry.
Common situations: Providers offering multiple credential types where the UI shows one upgrade button for all connections; scripts assuming all credentials for a provider are OAuth.
Related errors
- System credentials cannot be upgraded
- Credential provider does not match the requested provider
- 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/2f90bdfe80c68ce7.
Report an issue: GitHub.