fix(agents): expand embedded fallback classifier to accept transient provider errors#95537
Conversation
…provider errors - Rename classifyBusinessDenialErrorPayloadReason → classifyFailoverErrorPayloadReason - Add rate_limit, overloaded, server_error, timeout to fallback-eligible reasons - Add "upstream request failed" to serverError patterns in failover-matches - Add "type":"upstream_error" to isStructuredServerErrorMessage - Update tests: transient error payloads now trigger fallback instead of returning null Fixes openclaw#95519 Co-Authored-By: Claude <[email protected]>
|
Thanks for the context here. I swept through the related work, and this is now duplicate or superseded. Close as superseded: the open sibling PR is mergeable, maintainer-editable, proof-sufficient, and covers the same upstream_error fallback bug with a stronger structured-classifier approach, while this branch is now conflicting and still marked needs proof. Root-cause cluster Members:
Proposal only: this assessment does not dispatch repair, suppress jobs, mutate sibling items, close, or merge anything. Canonical path: Close this branch and keep maintainer review focused on the proof-sufficient mergeable sibling PR as the canonical landing path for the upstream_error fallback bug. So I’m closing this here because the remaining work is already tracked in the canonical issue. Review detailsBest possible solution: Close this branch and keep maintainer review focused on the proof-sufficient mergeable sibling PR as the canonical landing path for the upstream_error fallback bug. Do we have a high-confidence way to reproduce the issue? Yes at source level: current main routes embedded error payloads through a narrow business-denial helper, and model fallback stops when classifyResult returns null. I did not run live provider outage proof in this read-only review. Is this the best way to solve the issue? No. This branch is plausible, but the sibling PR is the better fix because it handles structured upstream_error through parsed error type classification, has sufficient proof, and is currently mergeable while this branch is conflicting. Security review: Security review cleared: The diff changes internal TypeScript fallback classification and tests only, with no dependency, workflow, package, secret, or code-execution surface change. AGENTS.md: found and applied where relevant. What I checked:
Likely related people:
Codex review notes: model internal, reasoning high; reviewed against d1b917120a47. |
|
Complementary observations on top of ClawSweeper's review: This fix is correct but narrower than the canonical sibling #95542. Two specific concerns:
|
|
ClawSweeper applied the proposed close for this PR.
|
Summary
When the primary provider returns an
upstream_error(e.g. "Upstream request failed"), OpenClaw ends the turn with "LLM request failed" instead of trying configured fallback models. The root cause is a two-layer gap: the error classifier only recognizedauth/billingpayloads as fallback-worthy, and the message pattern matcher did not include "upstream request failed" as a recognized server error.This PR fixes both layers:
Classifier filter (
result-fallback-classifier.ts): RenamesclassifyBusinessDenialErrorPayloadReason→classifyFailoverErrorPayloadReasonand expands the accepted reasons set to includerate_limit,overloaded,server_error, andtimeoutalongside the existingauth/auth_permanent/billing. Uses aSet<FailoverReason>for clarity and maintainability.Pattern matcher (
failover-matches.ts): Adds "upstream request failed" to theserverErrorpatterns list so that the bare text error from providers is recognized byclassifyFailoverClassificationFromMessage.Structured JSON matcher (
errors.ts): Adds"type":"upstream_error"toisStructuredServerErrorMessageso that full JSON error payloads with this type are classified asserver_error.Fixes #95519
Real behavior proof (required for external PRs)
Behavior addressed: Provider-side transient errors (upstream_error, HTTP 500, rate_limit, overload) now trigger the configured fallback chain instead of ending the turn with "LLM request failed".
Real setup tested:
Exact steps or command run after this patch:
After-fix evidence:
null(no fallback)timeoutfallback triggerednull(no fallback)timeoutfallback triggered{"type":"upstream_error",...}JSONnull(no fallback)server_errorfallback triggeredGit stats:
Observed result after the fix:
The fallback classifier now correctly identifies transient provider errors as fallback-eligible. Previously,
classifyFailoverErrorPayloadReason("Upstream request failed")returnednull; now it returns"timeout", which triggers the configured fallback chain.What was not tested:
classifyFailoverReasoninfrastructure, so all provider text variants benefit from the expanded classificationTests and validation
Risk checklist
Did user-visible behavior change?
Yes— Transient provider errors (upstream_error, rate_limit, overloaded, server_error, timeout) now trigger the configured fallback model chain instead of ending the turn. This matches documented fallback behavior.Did config, environment, or migration behavior change?
No— No configuration schema changes, no environment variables, no database migrations.Did security, auth, secrets, network, or tool execution behavior change?
No— Only affects fallback classification logic. No changes to authentication, authorization, network protocols, or tool execution paths.What is the highest-risk area?
How is that risk mitigated?
FALLBACKABLE_PROVIDER_ERROR_REASONS) — onlyauth,auth_permanent,billing,rate_limit,overloaded,server_error, andtimeoutare allowedformat,model_not_found,empty_response,unclassified) are explicitly excludedCurrent review state
What is the next action?
Related contributors (based on ClawSweeper analysis):
🤖 Generated with Claude Code