diff --git a/src/agents/failover-error.test.ts b/src/agents/failover-error.test.ts index 4e4379bf5da..ce372e4bc9b 100644 --- a/src/agents/failover-error.test.ts +++ b/src/agents/failover-error.test.ts @@ -22,6 +22,10 @@ const OPENROUTER_CREDITS_MESSAGE = "Payment Required: insufficient credits"; // https://github.com/openclaw/openclaw/issues/23440 const INSUFFICIENT_QUOTA_PAYLOAD = '{"type":"error","error":{"type":"insufficient_quota","message":"Your account has insufficient quota balance to run this request."}}'; +// Issue-backed ZhipuAI/GLM quota-exhausted log from #33785: +// https://github.com/openclaw/openclaw/issues/33785 +const ZHIPUAI_WEEKLY_MONTHLY_LIMIT_EXHAUSTED_MESSAGE = + "LLM error 1310: Weekly/Monthly Limit Exhausted. Your limit will reset at 2026-03-06 22:19:54 (request_id: 20260303141547610b7f574d1b44cb)"; // AWS Bedrock 429 ThrottlingException / 503 ServiceUnavailable: // https://docs.aws.amazon.com/bedrock/latest/userguide/troubleshooting-api-error-codes.html const BEDROCK_THROTTLING_EXCEPTION_MESSAGE = @@ -113,6 +117,14 @@ describe("failover-error", () => { ).toBe("billing"); }); + it("treats zhipuai weekly/monthly limit exhausted as rate_limit", () => { + expect( + resolveFailoverReasonFromError({ + message: ZHIPUAI_WEEKLY_MONTHLY_LIMIT_EXHAUSTED_MESSAGE, + }), + ).toBe("rate_limit"); + }); + it("infers format errors from error messages", () => { expect( resolveFailoverReasonFromError({ diff --git a/src/agents/pi-embedded-helpers.isbillingerrormessage.test.ts b/src/agents/pi-embedded-helpers.isbillingerrormessage.test.ts index dd8a38d2814..5c40bf58369 100644 --- a/src/agents/pi-embedded-helpers.isbillingerrormessage.test.ts +++ b/src/agents/pi-embedded-helpers.isbillingerrormessage.test.ts @@ -535,6 +535,9 @@ describe("classifyFailoverReason", () => { ).toBe("rate_limit"); expect(classifyFailoverReason("all credentials for model x are cooling down")).toBeNull(); expect(classifyFailoverReason("invalid request format")).toBe("format"); + expect( + classifyFailoverReason("HTTP 402 payment required. Your limit exhausted for this plan."), + ).toBe("billing"); expect(classifyFailoverReason(INSUFFICIENT_QUOTA_PAYLOAD)).toBe("billing"); expect(classifyFailoverReason("deadline exceeded")).toBe("timeout"); expect(classifyFailoverReason("request ended without sending any chunks")).toBe("timeout"); @@ -584,6 +587,14 @@ describe("classifyFailoverReason", () => { // but it should not be treated as provider overload / rate limit. expect(classifyFailoverReason("LLM error: service unavailable")).toBe("timeout"); }); + it("classifies zhipuai Weekly/Monthly Limit Exhausted as rate_limit (#33785)", () => { + expect( + classifyFailoverReason( + "LLM error 1310: Weekly/Monthly Limit Exhausted. Your limit will reset at 2026-03-06 22:19:54 (request_id: 20260303141547610b7f574d1b44cb)", + ), + ).toBe("rate_limit"); + expect(classifyFailoverReason("LLM error: weekly/monthly limit reached")).toBe("rate_limit"); + }); it("classifies permanent auth errors as auth_permanent", () => { expect(classifyFailoverReason("invalid_api_key")).toBe("auth_permanent"); expect(classifyFailoverReason("Your api key has been revoked")).toBe("auth_permanent"); diff --git a/src/agents/pi-embedded-helpers/failover-matches.ts b/src/agents/pi-embedded-helpers/failover-matches.ts index abbd6e769fa..686b81265c0 100644 --- a/src/agents/pi-embedded-helpers/failover-matches.ts +++ b/src/agents/pi-embedded-helpers/failover-matches.ts @@ -9,6 +9,7 @@ const ERROR_PATTERNS = { "quota exceeded", "resource_exhausted", "usage limit", + /weekly\/monthly limit/i, /\btpm\b/i, "tokens per minute", ],