fix #95519: [Bug]: Fallback should trigger on provider upstream_error / LLM request failed#95542
Conversation
|
Codex review: needs maintainer review before merge. Reviewed June 29, 2026, 7:02 AM ET / 11:02 UTC. Summary PR surface: Source +40, Tests +72. Total +112 across 4 files. Reproducibility: yes. at source level: current main routes embedded provider error payloads through a narrow allowlist and treats null classifications as completed primary attempts, so the reported upstream_error payload does not advance fallback. I did not run a live external provider outage reproduction in this read-only review. Review metrics: 1 noteworthy metric.
Root-cause cluster Members:
Proposal only: this assessment does not dispatch repair, suppress jobs, mutate sibling items, close, or merge anything. Merge readiness Overall follows the weaker of proof and patch quality, so missing proof can cap an otherwise strong patch. Risk before merge
Maintainer options:
Next step before merge
Security Review detailsBest possible solution: Use this PR or one explicitly chosen sibling as the canonical fix; if landing this PR, keep the scope to structured upstream/server/overloaded payloads and close or supersede overlapping PRs after merge. Do we have a high-confidence way to reproduce the issue? Yes at source level: current main routes embedded provider error payloads through a narrow allowlist and treats null classifications as completed primary attempts, so the reported upstream_error payload does not advance fallback. I did not run a live external provider outage reproduction in this read-only review. Is this the best way to solve the issue? Yes. The PR fixes the shared structured error-type mapping and the embedded payload allowlist rather than adding a config option, provider-specific workaround, or broad generic text match; canonical PR selection is the remaining maintainer decision. AGENTS.md: found and applied where relevant. Codex review notes: model internal, reasoning high; reviewed against 389c355bcf3f. Label changesLabel justifications:
Evidence reviewedPR surface: Source +40, Tests +72. Total +112 across 4 files. View PR surface stats
What I checked:
Likely related people:
What the crustacean ranks mean
Shiny media proof means a screenshot, video, or linked artifact directly shows the changed behavior. Runtime, network, CSP, and security claims still need visible diagnostics. How this review workflow works
|
|
Complementary observations on top of ClawSweeper's review: This is the most thorough fix in the #95519 cluster. The A few small things worth tightening before merge:
|
|
Additional live repro from a 2026.6.8 gateway setup, matching the failure mode this PR targets. Config shape: {
"agents": {
"defaults": {
"model": {
"primary": "<private-anthropic-compatible-primary>",
"fallbacks": ["<private-openai-compatible-fallback>"]
}
}
}
}Observed user-visible result: Session/error evidence for the failed primary attempt: A status check immediately after confirmed the fallback model was configured for the default primary, but the turn ended on the primary failure instead of advancing to the configured fallback. This was not a channel delivery failure; the same session could reply normally after being pinned to the fallback model. This looks like the same classifier gap as #95519, with the upstream provider failure surfaced as a terminal Local version where observed: |
|
Comparing the open #95519 fixes, this is the cleanest / most surgical of them, and it correctly handles the reported One small thing I noticed while reviewing the cluster: the matcher now maps Minor: the gate's return type was widened to (Context: I'd opened #96260 for the same issue but am closing it in favor of this one — sharing the finding here rather than piling on.) |
bd0d30c to
f5a70ef
Compare
|
Merged via squash.
|
…am_error / LLM request failed (openclaw#95542) * fix(agents): fallback on upstream provider errors * refactor(agents): clarify provider fallback classification --------- Co-authored-by: Altay <[email protected]> (cherry picked from commit cfd8ba8)
…am_error / LLM request failed (openclaw#95542) * fix(agents): fallback on upstream provider errors * refactor(agents): clarify provider fallback classification --------- Co-authored-by: Altay <[email protected]>
…am_error / LLM request failed (openclaw#95542) * fix(agents): fallback on upstream provider errors * refactor(agents): clarify provider fallback classification --------- Co-authored-by: Altay <[email protected]>
…am_error / LLM request failed (openclaw#95542) * fix(agents): fallback on upstream provider errors * refactor(agents): clarify provider fallback classification --------- Co-authored-by: Altay <[email protected]>
…am_error / LLM request failed (openclaw#95542) * fix(agents): fallback on upstream provider errors * refactor(agents): clarify provider fallback classification --------- Co-authored-by: Altay <[email protected]> (cherry picked from commit cfd8ba8)
…am_error / LLM request failed (openclaw#95542) * fix(agents): fallback on upstream provider errors * refactor(agents): clarify provider fallback classification --------- Co-authored-by: Altay <[email protected]>
…am_error / LLM request failed (openclaw#95542) * fix(agents): fallback on upstream provider errors * refactor(agents): clarify provider fallback classification --------- Co-authored-by: Altay <[email protected]> (cherry picked from commit cfd8ba8)
Fixes #95519
Summary
This PR fixes the provider-error classification gap exposed by issue #95519. When a primary model provider returned a structured transient upstream error, embedded agent execution could stop with
LLM request failedinstead of advancing through the already configured alternate model candidates.{"error":{"message":"Upstream request failed","type":"upstream_error","param":"","code":null}}are now classified as the existing transient server-error reason used by model failover.What Problem This Solves
Provider-side transient failures shaped as
upstream_errorcould end an embedded agent turn asLLM request failedeven when additional model candidates were configured. In that path, OpenClaw did not classify the structured provider error as failoverable, so the model routing chain could stop after the primary model attempt.Root Cause
upstream_errorpayloads into anyFailoverReason. Because that mapping was missing at the classification boundary, provider responses that were semantically transient upstream failures could be treated as non-deliverable terminal errors before the model routing code attempted the next configured candidate.FailoverReasonvalues, and then allows the embedded result classifier to consume that sameserver_errorreason for provider error payloads. This fixes the source mapping that decides whether model failover is allowed; it does not add a local retry, catch-all text match, or downstream workaround around the finalLLM request failedsymptom.Changes
errorType: "upstream_error"and JSON payloads witherror.type: "upstream_error"to the existingserver_errorfailover reason.server_errorpayloads, includingupstream_error, as candidate-switching provider failures.default/return nullbranches are intentional conservative guards: unrecognized provider error types remain non-failoverable. The new tests and comments describe the existing model failover behavior being protected; they do not broaden arbitrary provider text handling.Real behavior proof
node scripts/run-vitest.mjs src/agents/embedded-agent-helpers.formatassistanterrortext.test.ts src/agents/embedded-agent-runner/result-fallback-classifier.test.tswas run after formatting. A direct production-classifier proof was also run withnode --import tsx --input-type=moduleagainst the issue payload shape.server_errorreason for both the assistant error path and the embedded payload path;git diff --checkexited 0.upstream_error assistant reason: server_errorandembedded payload fallback reason: server_error, showing both production classification paths now feed the existing failover reason expected by the model routing chain.Regression Test Plan
src/agents/embedded-agent-helpers.formatassistanterrortext.test.tsandsrc/agents/embedded-agent-runner/result-fallback-classifier.test.ts.Upstream request failedwithtype: "upstream_error"; OpenClaw should classify it asserver_errorfor model failover instead of treating it as a non-failoverable terminal error.User Impact
LLM request failed. If every candidate fails, the existing summary behavior still reports the attempted models.Merge risk
server_error/upstream_errortypes and keeps auth, billing, hook blocks, replay-invalid turns, delivered replies, and unrelated terminal paths on their existing behavior.upstream_erroris a transient provider-side failure equivalent to the already failover-safe server-error class. Mapping it toserver_erroruses the existing model routing mechanism and preserves conservativenullbehavior for unknown error types, so compatibility risk is lower than adding a new reason, schema field, or generic text-based rule.Scope, contract, and compatibility
FailoverReasonclassification in the agent/provider error helpers and embedded result classifier.upstream_erroris normalized to the existingserver_errorreason rather than introducing a new public contract surface, config schema, protocol field, migration, or model-consumed payload shape.