Skip to content

OpenAI OAuth account plan_type remains Plus after usage_limit_reached reports free #2343

@XiaoYu994

Description

@XiaoYu994

Summary

OpenAI OAuth accounts can still be shown as Plus in the admin account list even after the upstream OpenAI response reports plan_type: "free" in a usage_limit_reached 429 response.

This makes the displayed account plan stale/misleading: the account is handled by OpenAI as a Free account, while Sub2API still displays the cached credentials.plan_type as Plus.

Environment

  • Repository: Wei-Shaw/sub2api
  • Observed on commit: dbc8ae6
  • Deployment: Docker image built from current main
  • Account type: OpenAI OAuth

Reproduction

  1. Have an OpenAI OAuth account whose local accounts.credentials.plan_type is cached as plus.
  2. Run the admin account test endpoint, for example POST /api/v1/admin/accounts/{id}/test, after the upstream account has become Free or has exhausted its Free usage window.
  3. OpenAI returns a 429 response like:
{
  "error": {
    "type": "usage_limit_reached",
    "message": "The usage limit has been reached",
    "plan_type": "free",
    "resets_at": 1778634027,
    "resets_in_seconds": 210842
  }
}
  1. The account list still shows Plus.

Actual Behavior

  • rate_limit_reset_at is updated correctly from resets_at.
  • credentials.plan_type remains the previous cached value, for example plus.
  • The frontend PlatformTypeBadge renders this stale planType and continues to show Plus.

Expected Behavior

When OpenAI returns error.plan_type in usage_limit_reached / related 429 responses, Sub2API should either:

  • persist the observed value to accounts.credentials.plan_type, especially when it changes to free; or
  • store/display an explicit observed/current plan state so the UI does not present stale cached subscription data as current.

Also, if subscription_expires_at is already in the past, the admin UI should probably avoid showing the cached Plus badge as a current plan unless a fresh account check confirms it.

Suspected Code Paths

  • backend/internal/service/account_test_service.go
    • reconcileOpenAI429State parses/reset-limits the 429 state but does not update plan_type.
  • backend/internal/service/ratelimit_service.go
    • parseOpenAIRateLimitResetTime parses reset fields from usage_limit_reached, but ignores error.plan_type.
  • frontend/src/components/common/PlatformTypeBadge.vue
    • renders planType directly from cached account credentials without checking staleness or expiry.

Notes

This is visible when an account was previously cached as Plus but OpenAI now responds with plan_type: "free". In that state, routing/limits should follow the upstream response, while the admin UI still suggests the account is Plus.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions