Compare commits

...

2 Commits

Author SHA1 Message Date
Shoubhit Dash 0ea9a00a3f docs(ai): describe quota codes provider-neutrally 2026-09-23 04:29:32 +05:30
Shoubhit Dash 25d0154d6d fix(ai): classify openai spend limits as quota exceeded 2026-09-23 04:22:37 +05:30
2 changed files with 16 additions and 1 deletions
+3 -1
View File
@@ -59,7 +59,7 @@ export const isContextOverflowFailure = (failure: unknown) =>
: Schema.is(ProviderErrorEvent)(failure) && failure.classification === "context-overflow"
const decodeJson = Schema.decodeUnknownOption(Schema.fromJsonString(Schema.Unknown))
// OpenCode Zen reports account caps as typed 429/402 errors that are not throttles.
// Account caps that providers and gateways report as typed 429/402 errors, not throttles.
const QUOTA_CODES = new Set([
"insufficient_quota",
"usage_not_included",
@@ -67,6 +67,8 @@ const QUOTA_CODES = new Set([
"gousagelimiterror",
"freeusagelimiterror",
"creditlimitexceeded",
"organization_spend_limit_exceeded",
"project_spend_limit_exceeded",
])
const AUTH_CODES = new Set(["authentication_error", "permission_error"])
const SERVER_CODES = new Set([
+13
View File
@@ -278,6 +278,19 @@ describe("provider error classification", () => {
).toEqual(Array(6).fill("QuotaExceeded"))
})
test("classifies OpenAI hard spend limits as quota rather than throttling", () => {
expect(
["organization_spend_limit_exceeded", "project_spend_limit_exceeded"].map(
(code) =>
classifyProviderFailure({
message: "Your project has reached its configured enforced spend limit.",
status: 429,
rawBody: JSON.stringify({ error: { code, message: "Spend limit reached." } }),
})._tag,
),
).toEqual(["QuotaExceeded", "QuotaExceeded"])
})
test("does not let substituted server codes make a 4xx retryable", () => {
const openai = { error: { type: "server_error", message: "Upstream request failed: Model is unavailable." } }
const anthropic = {