fix(error-classifier): quota/billing errors are non-retryable STOP (fixes #3126)

Add STOP_MESSAGE_PATTERNS that take precedence over RETRYABLE_MESSAGE_PATTERNS.
Message-only quota errors (no error name) now correctly return false from
isRetryableModelError, preventing unnecessary fallback retries on exhausted quotas.

- quota will reset after...
- quota exceeded
- usage limit has been reached
- free usage limit / billing limit / plan limit / subscription limit
- out of credits / credits exhausted / insufficient credits / insufficient balance

Also add 4 regression tests covering message-only quota STOP cases.
This commit is contained in:
YeonGyu-Kim
2026-04-06 16:56:05 +09:00
parent 9438c89c1c
commit f69234ab7e
2 changed files with 69 additions and 2 deletions
+44
View File
@@ -150,6 +150,50 @@ describe("model-error-classifier", () => {
expect(result).toBe(false)
})
test("treats quota reset message as non-retryable STOP error (no error name)", () => {
//#given
const error = { message: "quota will reset after 1 hour" }
//#when
const result = shouldRetryError(error)
//#then
expect(result).toBe(false)
})
test("treats quota exceeded message as non-retryable STOP error (no error name)", () => {
//#given
const error = { message: "quota exceeded for this billing period" }
//#when
const result = shouldRetryError(error)
//#then
expect(result).toBe(false)
})
test("treats usage limit reached message as non-retryable STOP error (no error name)", () => {
//#given
const error = { message: "usage limit has been reached for your account" }
//#when
const result = shouldRetryError(error)
//#then
expect(result).toBe(false)
})
test("treats insufficient credits message as non-retryable STOP error (no error name)", () => {
//#given
const error = { message: "insufficient credits to complete this request" }
//#when
const result = shouldRetryError(error)
//#then
expect(result).toBe(false)
})
test("treats 'bad request' message as retryable (GitHub Copilot rolling update)", () => {
//#given
const error = { message: "400 Bad Request" }