fix(failover): classify Moonshot balance 429 as billing#83079
Conversation
|
Codex review: needs maintainer review before merge. Workflow note: Future ClawSweeper reviews update this same comment in place. How this review workflow works
Summary Reproducibility: yes. at source level. Current main returns rate_limit for explicit HTTP 429 before the Moonshot/Kimi exhausted-balance payload can be preserved as billing, and the PR adds focused cases for that path. Real behavior proof Next step before merge Security Review detailsBest possible solution: Land the narrow provider-aware 429 classifier override with the regression test once the remaining checks finish green, then let the linked source issue close from the merge. Do we have a high-confidence way to reproduce the issue? Yes, at source level. Current main returns rate_limit for explicit HTTP 429 before the Moonshot/Kimi exhausted-balance payload can be preserved as billing, and the PR adds focused cases for that path. Is this the best way to solve the issue? Yes. The PR uses a narrow provider-scoped 429 exception and avoids reordering the shared message classifier, which is the lower-risk fix for this bug. Acceptance criteria:
What I checked:
Likely related people:
Remaining risk / open question:
Codex review notes: model gpt-5.5, reasoning high; reviewed against 543518bd43d7. |
|
Verified ClawSweeper's P1 finding locally — the fix as written cannot work because of matcher ordering. What I verified: I inspected the branch source at
Result: The test Suggested fix approaches:
Option A is narrower and avoids changing the shared message classifier ordering. It also means the Moonshot payload's Has anyone run the test suite on this branch? I expect |
|
Addressed the matcher-order finding in Verification added to the PR body: source-level RED/GREEN probe for Moonshot, Kimi provider hint, ordinary Moonshot 429, non-Moonshot 429, plus |
There was a problem hiding this comment.
Pull request overview
Narrow fix to ensure Moonshot/Kimi providers that return HTTP 429 with an "Insufficient account balance" payload are classified as billing rather than the generic rate_limit, so the UI can show recharge guidance and failover behavior is correct (fixes #43447).
Changes:
- Thread
providerintoclassifyFailoverClassificationFromHttpStatusand, in the 429 branch, returnbillingfor Moonshot/Kimi when the message is a billing-shaped error. - Add a regression test covering Moonshot/Kimi billing 429s, ordinary Moonshot 429s, and non-Moonshot 429 payloads.
- Add a CHANGELOG entry.
Reviewed changes
Copilot reviewed 3 out of 3 changed files in this pull request and generated no comments.
| File | Description |
|---|---|
| src/agents/pi-embedded-helpers/errors.ts | Adds provider-aware billing override before the 429 → rate_limit fallback. |
| src/agents/failover-error.test.ts | Adds coverage for the new Moonshot/Kimi billing-429 behavior. |
| CHANGELOG.md | Documents the fix. |
8377b4b to
dd05301
Compare
dd05301 to
f061e7d
Compare
f061e7d to
5856a6a
Compare
Preserve billing classification for Moonshot/Kimi HTTP 429 payloads that report insufficient account balance, while leaving ordinary 429 responses as rate_limit.
5856a6a to
9f70bf5
Compare
|
Merged via squash.
Thanks @leno23! |
Summary
rate_limit.rate_limit.Test Plan
node --import tsx ./tmp-openclaw-pr-83079-green-probe.mjsgit diff --checkOPENCLAW_VITEST_MAX_WORKERS=1 OPENCLAW_VITEST_NO_OUTPUT_TIMEOUT_MS=180000 node scripts/run-vitest.mjs run src/agents/failover-error.test.ts -t "lets Moonshot/Kimi billing-shaped 429 payloads win over generic rate limit status"(local runner stalled before test output; see Real behavior proof caveat)Real behavior proof
Behavior addressed: a Moonshot/Kimi response with HTTP 429 and an
Insufficient account balance/Please rechargepayload should surface asbilling, notrate_limit, so OpenClaw can show billing/recharge guidance instead of rate-limit behavior.Real environment tested: local OpenClaw source checkout using Node.js v22.18.0 after applying commit
14b33d7160f964a2f5606d5e37a8973bef216577on this PR branch. No live Moonshot credentials were used.Exact steps or command run after this patch: created a temporary repo-root probe that imports
src/agents/failover-error.tsandsrc/agents/pi-embedded-helpers/errors.ts, then rannode --import tsx ./tmp-openclaw-pr-83079-green-probe.mjs; also rangit diff --check.Evidence after fix:
Observed result after fix: Moonshot and Kimi billing-shaped 429 payloads resolve to
billing; an ordinary Moonshot 429 remainsrate_limit; the same balance-shaped 429 payload fromopenairemainsrate_limit;classifyFailoverSignal()returns{ kind: "reason", reason: "billing" }for the Moonshot balance-shaped 429 signal.What was not tested: live Moonshot/Kimi depleted-account behavior was not tested because this run has no provider credentials. The focused Vitest command stalled locally before producing test output (
no output for 180000ms; terminating stalled Vitest process group), so CI is expected to provide the official runner result.Risk / Notes
rate_limitrule.isBillingErrorMessage(message)directly inside the provider-specific 429 branch, instead of depending on the earlier message classification.Fixes #43447