From 12ce358da5ea190af1c3840e55d306f392d40c9a Mon Sep 17 00:00:00 2001 From: Daniel Sauer Date: Mon, 16 Feb 2026 23:32:45 +0100 Subject: [PATCH] fix(failover): recognize 'abort' stop reason as timeout for model fallback When streaming providers (GLM, OpenRouter, etc.) return 'stop reason: abort' due to stream interruption, OpenClaw's failover mechanism did not recognize this as a timeout condition. This prevented fallback models from being triggered, leaving users with failed requests instead of graceful failover. Changes: - Add abort patterns to ERROR_PATTERNS.timeout in pi-embedded-helpers/errors.ts - Extend TIMEOUT_HINT_RE regex to include abort patterns in failover-error.ts Fixes #18453 Co-authored-by: James --- src/agents/failover-error.ts | 3 ++- src/agents/pi-embedded-helpers/errors.ts | 3 +++ 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/src/agents/failover-error.ts b/src/agents/failover-error.ts index ddef89717..cfd9d37c4 100644 --- a/src/agents/failover-error.ts +++ b/src/agents/failover-error.ts @@ -1,6 +1,7 @@ import { classifyFailoverReason, type FailoverReason } from "./pi-embedded-helpers.js"; -const TIMEOUT_HINT_RE = /timeout|timed out|deadline exceeded|context deadline exceeded/i; +const TIMEOUT_HINT_RE = + /timeout|timed out|deadline exceeded|context deadline exceeded|stop reason:\s*abort|unhandled stop reason:\s*abort/i; const ABORT_TIMEOUT_RE = /request was aborted|request aborted/i; export class FailoverError extends Error { diff --git a/src/agents/pi-embedded-helpers/errors.ts b/src/agents/pi-embedded-helpers/errors.ts index ab1407668..98a740e2f 100644 --- a/src/agents/pi-embedded-helpers/errors.ts +++ b/src/agents/pi-embedded-helpers/errors.ts @@ -599,6 +599,9 @@ const ERROR_PATTERNS = { "deadline exceeded", "context deadline exceeded", /without sending (?:any )?chunks?/i, + /\bstop reason:\s*abort\b/i, + /\breason:\s*abort\b/i, + /\bunhandled stop reason:\s*abort\b/i, ], billing: [ /["']?(?:status|code)["']?\s*[:=]\s*402\b|\bhttp\s*402\b|\berror(?:\s+code)?\s*[:=]?\s*402\b|\b(?:got|returned|received)\s+(?:a\s+)?402\b|^\s*402\s+payment/i,