-
-
Notifications
You must be signed in to change notification settings - Fork 80.7k
[Bug]: Behavior bug (incorrect output/state without crash) #95574
Copy link
Copy link
Closed
Labels
P1High-priority user-facing bug, regression, or broken workflow.High-priority user-facing bug, regression, or broken workflow.bugSomething isn't workingSomething isn't workingbug:behaviorIncorrect behavior without a crashIncorrect behavior without a crashclawsweeper:linked-pr-openClawSweeper found an open linked pull request for this issue.ClawSweeper found an open linked pull request for this issue.clawsweeper:needs-live-reproClawSweeper needs live local, crabbox, or manual validation to confirm this issue.ClawSweeper needs live local, crabbox, or manual validation to confirm this issue.clawsweeper:needs-product-decisionClawSweeper marked this issue as needing a product or behavior decision.ClawSweeper marked this issue as needing a product or behavior decision.clawsweeper:no-new-fix-prClawSweeper does not recommend queueing a new automated fix PR for this issue.ClawSweeper does not recommend queueing a new automated fix PR for this issue.impact:auth-providerAuth, provider routing, model choice, or SecretRef resolution may break.Auth, provider routing, model choice, or SecretRef resolution may break.impact:message-lossChannel message delivery can be lost, duplicated, or misrouted.Channel message delivery can be lost, duplicated, or misrouted.issue-rating: 🐚 platinum hermitGood issue quality with a plausible reproduction path needing some confirmation.Good issue quality with a plausible reproduction path needing some confirmation.
Description
Metadata
Metadata
Assignees
Labels
P1High-priority user-facing bug, regression, or broken workflow.High-priority user-facing bug, regression, or broken workflow.bugSomething isn't workingSomething isn't workingbug:behaviorIncorrect behavior without a crashIncorrect behavior without a crashclawsweeper:linked-pr-openClawSweeper found an open linked pull request for this issue.ClawSweeper found an open linked pull request for this issue.clawsweeper:needs-live-reproClawSweeper needs live local, crabbox, or manual validation to confirm this issue.ClawSweeper needs live local, crabbox, or manual validation to confirm this issue.clawsweeper:needs-product-decisionClawSweeper marked this issue as needing a product or behavior decision.ClawSweeper marked this issue as needing a product or behavior decision.clawsweeper:no-new-fix-prClawSweeper does not recommend queueing a new automated fix PR for this issue.ClawSweeper does not recommend queueing a new automated fix PR for this issue.impact:auth-providerAuth, provider routing, model choice, or SecretRef resolution may break.Auth, provider routing, model choice, or SecretRef resolution may break.impact:message-lossChannel message delivery can be lost, duplicated, or misrouted.Channel message delivery can be lost, duplicated, or misrouted.issue-rating: 🐚 platinum hermitGood issue quality with a plausible reproduction path needing some confirmation.Good issue quality with a plausible reproduction path needing some confirmation.
Type
Fields
Priority
None yet
Bug type
Behavior bug (incorrect output/state without crash)
Beta release blocker
No
Summary
When an Ollama (or other harnessOwnsTransport) provider times out during a prompt, OpenClaw surfaces "LLM request timed out." directly to the user and never attempts the configured fallbacks list.
Steps to reproduce
Configure a local Ollama model as primary with at least one fallback:
"model": {
"primary": "ollama/qwen3.6:latest",
"fallbacks": [
"ollama/gemma4:26b",
"openrouter/google/gemini-2.5-flash",
"claude-cli/claude-sonnet-4-6"
]
}
Expected behavior
When a provider fails with a timeout and model.fallbacks is configured, OpenClaw should attempt the next model in the fallback chain, identical to its behavior on auth or billing failures.
Actual behavior
OpenClaw immediately surfaces "LLM request timed out." to the user. Trajectory records finalStatus: error, timedOut: true, promptErrorSource: prompt with no fallback attempt in traceAttempts.
Root cause traced to resolveRunFailoverDecision in embedded-agent-CpxCz9I4.js:
// Lines 711–714 — stage === "prompt" branch
if (params.harnessOwnsTransport && params.failoverReason === "timeout") return {
action: "surface_error", // ← fires before the fallbackConfigured check below
reason: params.failoverReason
};
// Line 719 — never reached when harnessOwnsTransport && timeout:
if (params.fallbackConfigured && params.failoverFailure && ...) return { action: "fallback_model" };
harnessOwnsTransport is true for all direct-API providers (Ollama, OpenRouter). The early return at line 711 preempts the fallbackConfigured guard entirely, so the fallback chain is never entered regardless of configuration.
The same logic blocks the assistant-stage path in shouldRotateAssistant (line 681):
if (params.harnessOwnsTransport && (timeoutFailure || params.failoverReason === "timeout")
&& !isConcreteNonTimeoutAssistantFailure(params)) return false; // assistantShouldRotate = false
The result-level classifier (result-fallback-classifier-CgsLfRqx.js) also misses it as a secondary safety net — classifyBusinessDenialErrorPayloadReason maps "timeout" to null (only "auth", "auth_permanent", "billing" are handled), and !isGpt5ModelId(model) gates out non-GPT-5 models before any catch-all.
Suggested minimal fix — add && !params.fallbackConfigured to line 711:
if (params.harnessOwnsTransport && params.failoverReason === "timeout" && !params.fallbackConfigured) return {
action: "surface_error",
reason: params.failoverReason
};
This preserves the existing surface_error behavior when no fallback is configured, while allowing the fallbackConfigured check at line 719 to fire when one is.
OpenClaw version
2026.6.5
Operating system
macOS 25.5.0
Install method
Homebrew (npm global via Homebrew)
Model
ollama/qwen3.6:latest
Provider / routing chain
openclaw → Ollama (http://localhost:11434) — harnessOwnsTransport: true
Additional provider/model setup details
Full fallback chain at time of failure:
primary: ollama/qwen3.6:latest
fallbacks: ollama/gemma4:26b
openrouter/google/gemini-2.5-flash
openrouter/meta-llama/llama-3.3-70b-instruct
claude-cli/claude-sonnet-4-6
models.providers.ollama.baseUrl: http://localhost:11434. No per-session model override was in effect for the failing session (override was on a different session key).
Logs, screenshots, and evidence
Impact and severity
Additional information
This is a related but distinct bug from the claude-cli out-of-credits fallback issue (where GENERIC_EXTERNAL_RUN_FAILURE_TEXT is emitted as visible text, causing hasVisibleAgentPayload() to return true and short-circuit the result-level classifier). That bug affects harnessOwnsTransport: false providers; this bug affects harnessOwnsTransport: true providers.
The idleTimedOut case (model silent, watchdog fires) is partially handled by the same-model retry at line 840 (allowSameModelIdleTimeoutRetry), but only when idleTimedOut = true. A full request timeout (timedOut: true, idleTimedOut: false) has no fallback path at all.