fix: recognize Venice 402 billing errors for model fallback (#43205)

Merged via squash.

Prepared head SHA: 1f6b10b9d9
Co-authored-by: Squabble9 <194720422+Squabble9@users.noreply.github.com>
Co-authored-by: altaywtf <9790196+altaywtf@users.noreply.github.com>
Reviewed-by: @altaywtf
This commit is contained in:
Squabble9
2026-03-12 02:15:32 +07:00
committed by GitHub
parent 01ffc5db24
commit 128e5bc317
3 changed files with 16 additions and 0 deletions

View File

@@ -108,6 +108,7 @@ Docs: https://docs.openclaw.ai
- Agents/cooldowns: default cooldown windows with no recorded failure history to `unknown` instead of `rate_limit`, avoiding false API rate-limit warnings while preserving cooldown recovery probes. (#42911) Thanks @VibhorGautam. - Agents/cooldowns: default cooldown windows with no recorded failure history to `unknown` instead of `rate_limit`, avoiding false API rate-limit warnings while preserving cooldown recovery probes. (#42911) Thanks @VibhorGautam.
- Discord/config typing: expose channel-level `autoThread` on the canonical guild-channel config type so strict config loading matches the existing Discord schema and runtime behavior. (#35608) Thanks @ingyukoh. - Discord/config typing: expose channel-level `autoThread` on the canonical guild-channel config type so strict config loading matches the existing Discord schema and runtime behavior. (#35608) Thanks @ingyukoh.
- Agents/error rendering: ignore stale assistant `errorMessage` fields on successful turns so background/tool-side failures no longer prepend synthetic billing errors over valid replies. (#40616) Thanks @ingyukoh. - Agents/error rendering: ignore stale assistant `errorMessage` fields on successful turns so background/tool-side failures no longer prepend synthetic billing errors over valid replies. (#40616) Thanks @ingyukoh.
- Agents/fallback: recognize Venice `402 Insufficient USD or Diem balance` billing errors so configured model fallbacks trigger instead of surfacing the raw provider error. (#43205) Thanks @Squabble9.
## 2026.3.8 ## 2026.3.8

View File

@@ -106,6 +106,9 @@ describe("isBillingErrorMessage", () => {
"Payment Required", "Payment Required",
"HTTP 402 Payment Required", "HTTP 402 Payment Required",
"plans & billing", "plans & billing",
// Venice returns "Insufficient USD or Diem balance" which has extra words
// between "insufficient" and "balance"
"Insufficient USD or Diem balance to complete request. Visit https://venice.ai/settings/api to add credits.",
]; ];
for (const sample of samples) { for (const sample of samples) {
expect(isBillingErrorMessage(sample)).toBe(true); expect(isBillingErrorMessage(sample)).toBe(true);
@@ -149,6 +152,11 @@ describe("isBillingErrorMessage", () => {
expect(longResponse.length).toBeGreaterThan(512); expect(longResponse.length).toBeGreaterThan(512);
expect(isBillingErrorMessage(longResponse)).toBe(false); expect(isBillingErrorMessage(longResponse)).toBe(false);
}); });
it("does not false-positive on short non-billing text that mentions insufficient and balance", () => {
const sample = "The evidence is insufficient to reconcile the final balance after compaction.";
expect(isBillingErrorMessage(sample)).toBe(false);
expect(classifyFailoverReason(sample)).toBeNull();
});
it("still matches explicit 402 markers in long payloads", () => { it("still matches explicit 402 markers in long payloads", () => {
const longStructuredError = const longStructuredError =
'{"error":{"code":402,"message":"payment required","details":"' + "x".repeat(700) + '"}}'; '{"error":{"code":402,"message":"payment required","details":"' + "x".repeat(700) + '"}}';
@@ -650,6 +658,12 @@ describe("classifyFailoverReason", () => {
expect(classifyFailoverReason(TOGETHER_ENGINE_OVERLOADED_MESSAGE)).toBe("overloaded"); expect(classifyFailoverReason(TOGETHER_ENGINE_OVERLOADED_MESSAGE)).toBe("overloaded");
expect(classifyFailoverReason(GROQ_TOO_MANY_REQUESTS_MESSAGE)).toBe("rate_limit"); expect(classifyFailoverReason(GROQ_TOO_MANY_REQUESTS_MESSAGE)).toBe("rate_limit");
expect(classifyFailoverReason(GROQ_SERVICE_UNAVAILABLE_MESSAGE)).toBe("overloaded"); expect(classifyFailoverReason(GROQ_SERVICE_UNAVAILABLE_MESSAGE)).toBe("overloaded");
// Venice 402 billing error with extra words between "insufficient" and "balance"
expect(
classifyFailoverReason(
"Insufficient USD or Diem balance to complete request. Visit https://venice.ai/settings/api to add credits.",
),
).toBe("billing");
}); });
it("classifies internal and compatibility error messages", () => { it("classifies internal and compatibility error messages", () => {

View File

@@ -52,6 +52,7 @@ const ERROR_PATTERNS = {
"credit balance", "credit balance",
"plans & billing", "plans & billing",
"insufficient balance", "insufficient balance",
"insufficient usd or diem balance",
], ],
authPermanent: [ authPermanent: [
/api[_ ]?key[_ ]?(?:revoked|invalid|deactivated|deleted)/i, /api[_ ]?key[_ ]?(?:revoked|invalid|deactivated|deleted)/i,