From 7df0c1607eadde399775ce0c5f0ec9dd2569ec9c Mon Sep 17 00:00:00 2001 From: Brendan DeBeasi Date: Thu, 26 Mar 2026 20:00:32 -0700 Subject: [PATCH] fix: auto-decay backoffLevel when rate limit window has passed MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit High backoffLevel (up to 15) persisted permanently in the DB after a burst of 429s. The account health score dropped to zero (100 - 15*10 = -50), causing the account selector to never pick the account again. Only a successful request could reset backoffLevel via clearAccountError, but the account was never selected — creating a deadlock. Now, during account selection, any non-terminal connection whose rateLimitedUntil has passed gets its backoffLevel reset to 0 and testStatus restored to active. The DB update is fire-and-forget to avoid blocking the hot path. Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-opencode) Co-authored-by: Sisyphus --- src/sse/services/auth.ts | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/src/sse/services/auth.ts b/src/sse/services/auth.ts index 757bff7d8e..20ba37e35e 100644 --- a/src/sse/services/auth.ts +++ b/src/sse/services/auth.ts @@ -368,6 +368,29 @@ export async function getProviderCredentials( return null; } + // Auto-decay backoffLevel for accounts whose rateLimitedUntil has passed. + // Without this, high backoffLevel permanently deprioritizes accounts even + // after the rate limit window expires, creating a deadlock where the account + // needs a successful request to reset but never gets selected. + for (const c of connections) { + if ( + c.backoffLevel > 0 && + !isTerminalConnectionStatus(c) && + !isAccountUnavailable(c.rateLimitedUntil) + ) { + c.backoffLevel = 0; + updateProviderConnection(c.id, { + backoffLevel: 0, + testStatus: "active", + lastError: null, + lastErrorAt: null, + lastErrorType: null, + lastErrorSource: null, + errorCode: null, + }).catch(() => {}); + } + } + // Filter out unavailable accounts and excluded connection const availableConnections = connections.filter((c) => { if (excludeConnectionId && c.id === excludeConnectionId) return false;