-
Notifications
You must be signed in to change notification settings - Fork 417
Description
Summary
When an LLM request hits the hard timeout (AbortError), the extension throws an error outside the fallback for loop, causing the full fallback model chain to be silently skipped. No fallback model is ever tried on timeout — only on provider errors (4xx/5xx).
Expected Behavior
On AbortError (request timeout), the loop should continue to the next model in the fallback chain — the same behavior that occurs when a provider returns a 4xx/5xx error.
Actual Behavior
The throw in the AbortError handler (around proxy.ts line 1102) exits the try/catch and the entire for loop. The full fallback chain configured in openclaw.json is never invoked on timeouts.
Steps to Reproduce
- Configure a multi-model fallback chain in
openclaw.json - Send a high-complexity request (long context + image attachments) that exceeds the
DEFAULT_REQUEST_TIMEOUT_MSthreshold - Observe: the primary model times out, no fallback model is attempted, the request fails with a hard
FailoverError
Root Cause
In proxy.ts, the AbortError catch block throws unconditionally:
if (err instanceof Error && err.name === "AbortError") throw new Error(`Request timed out...`)This throw exits the fallback for loop entirely instead of continue-ing to the next model.
Suggested Fix
Move the timeout handler inside the fallback loop so it can continue to the next model:
// Inside the fallback for loop
if (err instanceof Error && err.name === "AbortError") {
console.warn(`Model ${modelId} timed out, trying next fallback...`);
continue; // instead of throw
}Environment
- OpenClaw gateway with ClawRouter extension
- Fallback chain:
claude-max/claude-sonnet-4→claude-max/claude-opus-4→openai-codex/gpt-5.3-codex→ (additional fallbacks) - Hard timeout:
DEFAULT_REQUEST_TIMEOUT_MS(~180–300s) - Observed: 7+ timeout failures in a single session, all skipping the fallback chain
Impact
Users relying on fallback chains for reliability get hard failures on timeout instead of automatic model fallover. This defeats the purpose of the fallback configuration.