From 587557121536ad6ffa62b9ca5a255caebadb6add Mon Sep 17 00:00:00 2001 From: QTom Date: Sat, 21 Mar 2026 18:45:00 +0800 Subject: [PATCH] =?UTF-8?q?fix(ratelimit):=20OpenAI=20401=20token=5Finvali?= =?UTF-8?q?dated/token=5Frevoked=20=E5=8F=8A=20402=20deactivated=5Fworkspa?= =?UTF-8?q?ce=20=E6=A0=87=E8=AE=B0=E8=B4=A6=E5=8F=B7=E5=BC=82=E5=B8=B8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 401 token_invalidated / token_revoked: OAuth token 被永久作废,跳过临时不可调度逻辑,直接 SetError - 402 deactivated_workspace: 解析 detail.code 字段,标记工作区已停用 Co-Authored-By: Claude Opus 4.6 (1M context) --- backend/internal/service/ratelimit_service.go | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/backend/internal/service/ratelimit_service.go b/backend/internal/service/ratelimit_service.go index afe5816d..aa0ae200 100644 --- a/backend/internal/service/ratelimit_service.go +++ b/backend/internal/service/ratelimit_service.go @@ -12,6 +12,7 @@ import ( "github.com/Wei-Shaw/sub2api/internal/config" "github.com/Wei-Shaw/sub2api/internal/pkg/logger" + "github.com/tidwall/gjson" ) // RateLimitService 处理限流和过载状态管理 @@ -149,6 +150,17 @@ func (s *RateLimitService) HandleUpstreamError(ctx context.Context, account *Acc } // 其他 400 错误(如参数问题)不处理,不禁用账号 case 401: + // OpenAI: token_invalidated / token_revoked 表示 token 被永久作废(非过期),直接标记 error + openai401Code := extractUpstreamErrorCode(responseBody) + if account.Platform == PlatformOpenAI && (openai401Code == "token_invalidated" || openai401Code == "token_revoked") { + msg := "Token revoked (401): account authentication permanently revoked" + if upstreamMsg != "" { + msg = "Token revoked (401): " + upstreamMsg + } + s.handleAuthError(ctx, account, msg) + shouldDisable = true + break + } // OAuth 账号在 401 错误时临时不可调度(给 token 刷新窗口);非 OAuth 账号保持原有 SetError 行为。 // Antigravity 除外:其 401 由 applyErrorPolicy 的 temp_unschedulable_rules 自行控制。 if account.Type == AccountTypeOAuth && account.Platform != PlatformAntigravity { @@ -192,6 +204,13 @@ func (s *RateLimitService) HandleUpstreamError(ctx context.Context, account *Acc shouldDisable = true } case 402: + // OpenAI: deactivated_workspace 表示工作区已停用,直接标记 error + if account.Platform == PlatformOpenAI && gjson.GetBytes(responseBody, "detail.code").String() == "deactivated_workspace" { + msg := "Workspace deactivated (402): workspace has been deactivated" + s.handleAuthError(ctx, account, msg) + shouldDisable = true + break + } // 支付要求:余额不足或计费问题,停止调度 msg := "Payment required (402): insufficient balance or billing issue" if upstreamMsg != "" {