Significant-Gravitas/AutoGPT · warning · HTTPException
ENTERPRISE subscription changes must be managed by an admini
Error message
ENTERPRISE subscription changes must be managed by an administrator
What it means
HTTP 403 from POST /credits/subscription when the caller's current subscription_tier is ENTERPRISE. Enterprise contracts are provisioned and changed by administrators (custom Stripe pricing, invoices, contracts), so self-service tier changes are blocked for those users regardless of the requested target tier.
Source
Thrown at autogpt_platform/backend/backend/api/features/v1.py:1086
async def update_subscription_tier(
request: SubscriptionTierRequest,
user_id: Annotated[str, Security(get_user_id)],
x_datafast_visitor_id: Annotated[
str | None, Header(include_in_schema=False)
] = None,
x_datafast_session_id: Annotated[
str | None, Header(include_in_schema=False)
] = None,
) -> SubscriptionStatusResponse:
# Pydantic validates tier is one of BASIC/PRO/MAX/BUSINESS via Literal type.
tier = SubscriptionTier(request.tier)
# ENTERPRISE tier is admin-managed — block self-service changes from ENTERPRISE users.
user = await get_user_by_id(user_id)
if (
user.subscription_tier or SubscriptionTier.NO_TIER
) == SubscriptionTier.ENTERPRISE:
raise HTTPException(
status_code=403,
detail="ENTERPRISE subscription changes must be managed by an administrator",
)
# Same-tier + same-cycle request = "stay on my current tier" = cancel any
# pending scheduled change (paid→paid downgrade or paid→BASIC cancel). This
# replaces the old /credits/subscription/cancel-pending route. Safe when no
# pending change exists: release_pending_subscription_schedule returns
# False and we simply return the current status.
#
# Same-tier-DIFFERENT-cycle (monthly Pro → yearly Pro, or vice versa) must
# fall through to modify_stripe_subscription_for_tier so Stripe swaps the
# price ID for the cycle the user actually requested.
#
# Gate the short-circuit on an actual active/trialing Stripe subscription:
# admin-granted tiers (DB tier set, no Stripe sub) must fall through to the
# Checkout flow so "start paying for my current tier" is not a no-op.
current_tier = user.subscription_tier or SubscriptionTier.NO_TIERView on GitHub (pinned to 9c8bb5550f)
Solutions
- Hide the self-service subscription controls in the frontend when the current tier is ENTERPRISE
- Contact the platform administrator / support to change an ENTERPRISE subscription
- For testing: have an admin reset the user's tier before retrying self-service flows
Defensive patterns
Strategy: type-guard
Type guard
function canSelfServeSubscription(tier: SubscriptionTier): boolean {
return tier !== "ENTERPRISE";
} Try / catch
try { await api.setSubscription(req); }
catch (e) { if (e.status === 403 && /ENTERPRISE/.test(e.detail)) showContactAdmin(); else throw e; } Prevention
- Gate tier-change UI on the current tier from GET /credits/subscription
- Show 'managed by your administrator' messaging for ENTERPRISE users
When it happens
Trigger: Any POST /credits/subscription (upgrade, downgrade, or cancel) issued by a user whose user.subscription_tier == ENTERPRISE.
Common situations: Enterprise users clicking through the pricing page after their org was migrated to ENTERPRISE; stale frontend still showing tier-change buttons for enterprise accounts; test users upgraded to ENTERPRISE by an admin script while old UI sessions remain open.
Related errors
- job belongs to a different user
- This invitation was sent to a different email address
- Not a member of this organization
- Failed to start OAuth flow
- Failed to fetch rate limit
AI-assisted analysis of Significant-Gravitas/AutoGPT@9c8bb5550f (2026-08-14).
Data as JSON: /api/errors/3f33f8954ad4c6be.
Report an issue: GitHub.