From 801a0dd302f6a8112a9be8abf583a86a5d96df7b Mon Sep 17 00:00:00 2001 From: roboomp Date: Sun, 21 Jun 2026 05:24:06 +0000 Subject: [PATCH] fix(ai): classified dashscope throttles as rate limits Prioritized rate-limit wording before auth wording in auth-gateway error classification so DashScope throttling messages that contain unauthorized do not invalidate credentials. Fixes #3172 --- packages/ai/CHANGELOG.md | 4 ++++ packages/ai/src/auth-gateway/server.ts | 10 ++++++---- packages/ai/test/auth-gateway-classify-error.test.ts | 6 ++++++ 3 files changed, 16 insertions(+), 4 deletions(-) diff --git a/packages/ai/CHANGELOG.md b/packages/ai/CHANGELOG.md index f08a1da86..32a9d97fa 100644 --- a/packages/ai/CHANGELOG.md +++ b/packages/ai/CHANGELOG.md @@ -2,6 +2,10 @@ ## [Unreleased] +### Fixed + +- Fixed DashScope 429 rate-limit messages that mention authorization being classified as credential failures, preventing valid API keys from being invalidated after throttling. ([#3172](https://github.com/can1357/oh-my-pi/issues/3172)) + ## [16.1.9] - 2026-06-21 ### Added diff --git a/packages/ai/src/auth-gateway/server.ts b/packages/ai/src/auth-gateway/server.ts index a05d00bf7..d44a20b73 100644 --- a/packages/ai/src/auth-gateway/server.ts +++ b/packages/ai/src/auth-gateway/server.ts @@ -229,11 +229,10 @@ export function classifyGatewayError(err: unknown): { status: number; type: stri if (/\baborted\b|\babort signal\b/i.test(message)) { return { status: 499, type: "request_aborted", message }; } - if (/\b(?:unauthorized|forbidden)\b/i.test(message)) { - return { status: 401, type: "authentication_error", message }; - } if ( - // Match rate-limit phrasings without colliding with + // Match rate-limit phrasings before auth wording: some providers + // describe throttling as "unauthorized due to rate limit". + // Keep boundaries so this does not collide with // `GenerateContentRequest`, `accelerate`, `iterate`, `deprecated`, etc. /\brate[- _]?limit(?:s|ed|ing)?\b|\bquota(?:_exceeded| exceeded)?\b|\btoo[- _]many[- _]requests\b/i.test( message, @@ -249,6 +248,9 @@ export function classifyGatewayError(err: unknown): { status: number; type: stri ) { return { status: 429, type: "rate_limit_error", message }; } + if (/\b(?:unauthorized|forbidden)\b/i.test(message)) { + return { status: 401, type: "authentication_error", message }; + } if (/\b(?:unsupported|invalid_request|invalid request|bad request|malformed)\b/i.test(message)) { return { status: 400, type: "invalid_request_error", message }; } diff --git a/packages/ai/test/auth-gateway-classify-error.test.ts b/packages/ai/test/auth-gateway-classify-error.test.ts index e55fdf602..a499da6d8 100644 --- a/packages/ai/test/auth-gateway-classify-error.test.ts +++ b/packages/ai/test/auth-gateway-classify-error.test.ts @@ -54,6 +54,12 @@ describe("auth-gateway classifyGatewayError", () => { expect(c.type).toBe("rate_limit_error"); }); + it("prefers rate-limit wording over auth wording", () => { + const c = classifyGatewayError(new Error("Rate limit exceeded - unauthorized due to throttling")); + expect(c.status).toBe(429); + expect(c.type).toBe("rate_limit_error"); + }); + it("classifies Codex 'You have hit your ChatGPT usage limit' as 429", () => { // Verbatim shape Codex returns from the `usage_limit_reached` branch // in `parseCodexError`. No embedded `HTTP NNN`/`(NNN)`/`status NNN`