Skip to content

fix(agent-runner): classify transient provider errors as fallback-worthy#95594

Closed
mmyzwl wants to merge 3 commits into
openclaw:mainfrom
mmyzwl:fix/issue-95519-bug-fallback-should-trigger-on-provider-upstream-error-llm-r
Closed

fix(agent-runner): classify transient provider errors as fallback-worthy#95594
mmyzwl wants to merge 3 commits into
openclaw:mainfrom
mmyzwl:fix/issue-95519-bug-fallback-should-trigger-on-provider-upstream-error-llm-r

Conversation

@mmyzwl

@mmyzwl mmyzwl commented Jun 21, 2026

Copy link
Copy Markdown
Contributor

Summary

When a primary provider returns an upstream_error / HTTP 500 / transient server error, the embedded agent run result classifier discards it (returns null), so runWithModelFallback never advances to the next configured fallback model. The turn ends immediately with LLM request failed even when healthy fallback models are configured and ready.

Fixes #95519

Changes

  • result-fallback-classifier.ts: Renamed classifyBusinessDenialErrorPayloadReasonclassifyProviderErrorPayloadReason and extended the switch statement to also pass through server_error and timeout failover reasons (previously only auth/auth_permanent/billing were passed through).
  • result-fallback-classifier.test.ts: Updated the "does not retry non-business transport error payloads" test case to expect a proper fallback classification for HTTP 500: internal server error instead of null.

Real behavior proof

Behavior addressed: Provider transient errors (upstream_error, HTTP 500, server timeout) now correctly trigger configured model fallbacks instead of ending the turn immediately.

Evidence type: terminal

Real setup tested: Node v24.13.1, Linux x86_64, worktree branch on openclaw/openclaw@main

Exact steps or command run after this patch:

node scripts/test-projects.mjs src/agents/embedded-agent-runner/result-fallback-classifier.test.ts
node scripts/test-projects.mjs src/agents/outcome-fallback-runtime-contract.test.ts
node scripts/test-projects.mjs src/agents/model-fallback.test.ts

After-fix evidence:

$ CI=true pnpm test -- src/agents/embedded-agent-runner/result-fallback-classifier.test.ts

 Test Files  1 passed (1)
      Tests  11 passed (11)

$ CI=true pnpm test -- src/agents/outcome-fallback-runtime-contract.test.ts

 Test Files  1 passed (1)
      Tests  10 passed (10)

$ CI=true pnpm test -- src/agents/model-fallback.test.ts

 Test Files  1 passed (1)
      Tests  82 passed (82)

Observed result after the fix: All 103 tests pass across 3 related test suites. The classifier now correctly identifies server_error and timeout provider errors as fallback-worthy alongside the existing auth/auth_permanent/billing classifications.

What was not tested: Live end-to-end verification with a real provider returning upstream_error was not performed. The fix is validated at the unit-test layer which directly covers the classification code path.

Tests and validation

Test Type Result Details
result-fallback-classifier 11/11 passed
outcome-fallback-runtime-contract 10/10 passed
model-fallback 82/82 passed

Risk checklist

Did user-visible behavior change? (Yes / No)

Yes — users with configured fallback models will now see automatic fallback on transient provider errors (upstream_error, HTTP 500, timeouts) instead of immediate turn failure. This is the intended fix.

Did config, environment, or migration behavior change? (Yes / No)

No

Did security, auth, secrets, network, or tool execution behavior change? (Yes / No)

No — only the internal fallback classification path is changed; auth/auth_permanent errors already triggered fallback before this change.

What is the highest-risk area?

  • Over-fallbacking if the classifier is too broad

How is that risk mitigated?

  • Only server_error and timeout (two specific transient errors already identified by the existing classifyFailoverReason function) are added. All other classifications (format, rate_limit, overloaded, model_not_found, etc.) remain filtered out as before. The non-GPT model fallthrough path is unchanged.

Current review state

What is the next action?

  • Maintainer review

Extend the embedded error payload classifier to treat server_error and
timeout failover reasons as fallback-worthy alongside the existing
auth/auth_permanent/billing classifications.

Previously, transient provider errors such as upstream_error / HTTP 500
were discarded by the classifier (returning null), which prevented
runWithModelFallback from advancing to the next configured fallback
model. The result was an immediate turn failure even when healthy
fallback models were configured.

Changes:
- Rename classifyBusinessDenialErrorPayloadReason to
  classifyProviderErrorPayloadReason
- Add server_error and timeout to the pass-through switch cases
- Update the corresponding test: HTTP 500 now triggers fallback
  instead of returning null

Fixes openclaw#95519
@openclaw-barnacle openclaw-barnacle Bot added agents Agent runtime and tooling size: XS labels Jun 21, 2026
@clawsweeper

clawsweeper Bot commented Jun 21, 2026

Copy link
Copy Markdown
Contributor

Thanks for the context here. I did a careful shell check against current main, and this is already implemented.

Close: current main already implements the linked upstream_error fallback fix through #95542, and this stale conflicting branch is no longer the right landing path.

Root-cause cluster
Relationship: superseded
Canonical: #95542
Summary: The upstream_error fallback bug was fixed by the merged canonical PR; this PR is an overlapping stale candidate with a broader leftover timeout/HTTP 500 policy change.

Members:

Proposal only: this assessment does not dispatch repair, suppress jobs, mutate sibling items, close, or merge anything.

So I’m closing this as already implemented rather than keeping a duplicate issue open.

Review details

Best possible solution:

Keep the current main implementation from #95542; any broader bare HTTP 500/timeout fallback policy should be proposed separately with focused proof.

Do we have a high-confidence way to reproduce the issue?

Yes. The linked bug is source-reproducible through the structured upstream_error payload classifier and the runWithModelFallback caller path, and current main now has regression coverage for that path.

Is this the best way to solve the issue?

No. This PR is no longer the best landing path because current main already has the narrower canonical fix, while this branch is conflicting and also changes bare HTTP 500 behavior that current tests still keep conservative.

Security review:

Security review cleared: The PR diff only changes internal TypeScript fallback classification and tests, with no dependency, workflow, secret, package, or code-execution surface changes.

AGENTS.md: found and applied where relevant.

What I checked:

Likely related people:

  • mikasa0818: Authored the merged canonical fix commit for the linked upstream_error fallback bug, which touched the same classifier and tests. (role: canonical fix author; confidence: high; commits: cfd8ba8fc81d, e67b78af640f; files: src/agents/embedded-agent-helpers/errors.ts, src/agents/embedded-agent-runner/result-fallback-classifier.ts, src/agents/embedded-agent-runner/result-fallback-classifier.test.ts)
  • altaywtf: The merged canonical PR includes Altay's follow-up refactor clarifying the provider fallback classification boundary before merge. (role: canonical fix refactor author; confidence: high; commits: f5a70ef7bb10, cfd8ba8fc81d; files: src/agents/embedded-agent-helpers/errors.ts, src/agents/embedded-agent-runner/result-fallback-classifier.ts)
  • steipete: Recent GitHub commit history shows repeated work on model fallback, terminal classifiers, and model-failover docs that define this behavior boundary. (role: fallback area contributor; confidence: medium; commits: 0314819f918a, 6719528316c0, e8895f0a9958; files: src/agents/model-fallback.ts, src/agents/embedded-agent-runner/result-fallback-classifier.ts, docs/concepts/model-failover.md)
  • vincentkoc: Recent model-fallback history includes shared error-normalization and fallback wiring work, and the v2026.7.1-beta.1 release tag was created by Vincent Koc. (role: recent adjacent contributor; confidence: medium; commits: 80805ad7a583, aa3797c8d0d7, 3ffb1b362d71; files: src/agents/model-fallback.ts, src/agents/embedded-agent-helpers/errors.ts)

Codex review notes: model internal, reasoning high; reviewed against 328fb70ba730; fix evidence: release v2026.7.1-beta.1, commit cfd8ba8fc81d.

@clawsweeper clawsweeper Bot added rating: 🧂 unranked krab Not merge-ready due to missing proof or serious correctness/safety concerns. status: 📣 needs proof The PR needs real behavior proof before ClawSweeper can clear the contributor ask. P2 Normal backlog priority with limited blast radius. merge-risk: 🚨 message-delivery 🚨 May drop, duplicate, misroute, suppress, or wrongly target messages. labels Jun 21, 2026
…ification

Add classifyFailoverReasonFromErrorType to parse structured provider
error payloads by their errorType field (upstream_error, server_error),
and integrate it into the classifyFailoverSignal pipeline so that
transient upstream failure payloads like
{"error":{"type":"upstream_error",...}} are classified as server_error
instead of falling through unclassified.

Also extend isStructuredServerErrorMessage to match upstream_error
type/code patterns in raw error text.

This complements the downstream classifier change (classifyProviderErrorPayloadReason)
that allows server_error and timeout to trigger model fallback.

Adds test coverage for:
- classifyAssistantFailoverReason with upstream_error payloads
- classifyEmbeddedAgentRunResultForModelFallback with structured
  upstream_error payloads

Refs openclaw#95519
@mmyzwl

mmyzwl commented Jun 21, 2026

Copy link
Copy Markdown
Contributor Author

Updated with upstream error type classification (classifyFailoverReasonFromErrorType) plus extended downstream classifier allowlist. All 191 tests pass across 4 test suites. Please re-review.

@clawsweeper clawsweeper Bot added rating: 🦪 silver shellfish Thin PR readiness signal; proof, validation, or implementation needs work. rating: 🧂 unranked krab Not merge-ready due to missing proof or serious correctness/safety concerns. status: 🛠️ actively grinding The PR author has acted after the latest ClawSweeper review and work remains. and removed rating: 🧂 unranked krab Not merge-ready due to missing proof or serious correctness/safety concerns. rating: 🦪 silver shellfish Thin PR readiness signal; proof, validation, or implementation needs work. status: 📣 needs proof The PR needs real behavior proof before ClawSweeper can clear the contributor ask. labels Jun 21, 2026
@mmyzwl

mmyzwl commented Jun 21, 2026

Copy link
Copy Markdown
Contributor Author

@clawsweeper re-review

@clawsweeper

clawsweeper Bot commented Jun 21, 2026

Copy link
Copy Markdown
Contributor

🦞🧹
ClawSweeper re-review requested.

I asked ClawSweeper to review this item again.
Action: item re-review queued (workflow sweep.yml, event repository_dispatch).
Result: the existing ClawSweeper review comment will be edited in place when the review finishes.

@clawsweeper clawsweeper Bot added status: 📣 needs proof The PR needs real behavior proof before ClawSweeper can clear the contributor ask. merge-risk: 🚨 auth-provider 🚨 May break OAuth, tokens, provider routing, model choice, or credentials. and removed status: 🛠️ actively grinding The PR author has acted after the latest ClawSweeper review and work remains. labels Jun 21, 2026
@mmyzwl

mmyzwl commented Jun 21, 2026

Copy link
Copy Markdown
Contributor Author

@clawsweeper re-review

@clawsweeper

clawsweeper Bot commented Jul 2, 2026

Copy link
Copy Markdown
Contributor

@mmyzwl thanks for the PR. ClawSweeper is still waiting on real behavior proof before this can move forward.

Useful proof can be a screenshot, short video, terminal output, copied live output, linked artifact, or redacted logs that show the changed behavior after the fix. Please redact private tokens, phone numbers, private endpoints, customer data, and anything else sensitive.

Once proof is added to the PR body or a comment, ClawSweeper or a maintainer can re-check it.

@clawsweeper

clawsweeper Bot commented Jul 3, 2026

Copy link
Copy Markdown
Contributor

ClawSweeper applied the proposed close for this PR.

@clawsweeper clawsweeper Bot closed this Jul 3, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

agents Agent runtime and tooling merge-risk: 🚨 auth-provider 🚨 May break OAuth, tokens, provider routing, model choice, or credentials. merge-risk: 🚨 message-delivery 🚨 May drop, duplicate, misroute, suppress, or wrongly target messages. P2 Normal backlog priority with limited blast radius. rating: 🧂 unranked krab Not merge-ready due to missing proof or serious correctness/safety concerns. size: S status: 📣 needs proof The PR needs real behavior proof before ClawSweeper can clear the contributor ask.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Bug]: Fallback should trigger on provider upstream_error / LLM request failed

1 participant