-
-
Notifications
You must be signed in to change notification settings - Fork 52.7k
Description
Summary
Model fallback doesn't trigger when the primary Antigravity model times out. The AbortError from session.abort() escapes via waitForCompactionRetry() and bypasses the fallback mechanism in runWithModelFallback().
Steps to reproduce
- Configure fallback models in
~/.clawdbot/clawdbot.json:"agent": { "model": { "primary": "google-antigravity/claude-opus-4-5-thinking", "fallbacks": ["google-antigravity/gemini-3-pro-low", "google-antigravity/gemini-3-flash"] } }
- Send a message that triggers an agent run when the primary model is slow/rate-limited
- Wait for timeout (10 minutes) - observe no fallback models are tried
Expected behavior
After the primary model times out, clawdbot should automatically try fallback models in order until one succeeds, then return the response from whichever model worked.
Actual behavior
Timeout triggers session.abort() → throws AbortError → escapes from waitForCompactionRetry() (outside try/catch) → model-fallback.ts:199 sees AbortError and immediately re-throws without trying fallbacks → request fails with "Request was aborted".
The fallback models are never attempted.
Environment
- Clawdbot version: 2026.1.5-3
- OS: macOS Darwin 25.1.0 (arm64)
- Install method: pnpm (source)
Logs or screenshots
[agent/embedded] embedded run timeout: runId=d6165b71-abc5-420c-95b7-00c41675d877 sessionId=24e1c3c4-a457-463c-94d6-abfd17868d8c timeoutMs=600000
[agent/embedded] Profile google-antigravity:xxx@gmail.com timed out (possible rate limit). Trying next account...
Embedded agent failed before reply: Request was aborted
[gws] ⇄ res ✗ chat.send 600248ms errorCode=UNAVAILABLE errorMessage=Error: Request was aborted
Root cause analysis
In pi-embedded-runner.ts, waitForCompactionRetry() at line 899 is outside the try/catch that captures promptError:
try {
await session.prompt(params.prompt);
} catch (err) {
promptError = err; // Only catches errors from session.prompt()
}
await waitForCompactionRetry(); // This can ALSO throw AbortError!When timeout fires:
abortRun(true)is called → setstimedOut = trueand callssession.abort()session.prompt()throws AbortError → caught inpromptErrorwaitForCompactionRetry()ALSO throws AbortError → NOT caught, escapes!model-fallback.ts:199:if (isAbortError(err)) throw err;→ bypasses fallback
Proposed fix
Wrap waitForCompactionRetry() in its own try/catch:
try {
await waitForCompactionRetry();
} catch (err) {
if (!promptError) promptError = err;
}This ensures the AbortError is captured as promptError, allowing the timeout handling logic at line 970+ to throw a regular Error("LLM request timed out.") that triggers the model fallback mechanism.