From 689b5dc6c369ca33d17c822433346e6c0404e522 Mon Sep 17 00:00:00 2001 From: luvs01 Date: Sat, 8 Aug 2026 19:25:45 +0900 Subject: [PATCH] fix(oauth): clear transient Anthropic refresh intent --- src/oauth/index.ts | 7 +++++-- tests/oauth-refresh.test.ts | 8 +++++++- 2 files changed, 12 insertions(+), 3 deletions(-) diff --git a/src/oauth/index.ts b/src/oauth/index.ts index 3487023929..3ea095816e 100644 --- a/src/oauth/index.ts +++ b/src/oauth/index.ts @@ -525,8 +525,11 @@ export async function refreshAnthropicAccountWithLock( clearOAuthRefreshIntent(provider, accountId, generation); return fresh.access; } catch (error) { - if (error instanceof OAuthMutationBusyError) throw error; - if (!terminal(error)) throw error; + if (error instanceof OAuthMutationBusyError || error instanceof OAuthTokenRefreshStaleError) throw error; + if (!terminal(error)) { + clearOAuthRefreshIntent(provider, accountId, generation); + throw error; + } await markAccountNeedsReauthIfGeneration(provider, accountId, generation, writerGeneration); clearOAuthRefreshIntent(provider, accountId, generation); throw new OAuthLoginRequiredError(provider); diff --git a/tests/oauth-refresh.test.ts b/tests/oauth-refresh.test.ts index 4799a3431b..ac0a126cb4 100644 --- a/tests/oauth-refresh.test.ts +++ b/tests/oauth-refresh.test.ts @@ -475,7 +475,7 @@ describe("oauth refresh hardening", () => { expect(getCredential("xai")?.source).toBe("oauth"); }); - test("Anthropic transient failures do not mark needsReauth", async () => { + test("Anthropic transient failures remain retryable without marking needsReauth", async () => { for (const [index, error] of [ new AnthropicTokenError("server", 503, undefined), new AnthropicTokenError("timeout", undefined, undefined), @@ -484,6 +484,12 @@ describe("oauth refresh hardening", () => { const id = getAccountSet("anthropic")!.activeAccountId; await expect(refreshAnthropicAccountWithLock("anthropic", id, { ...OAUTH_PROVIDERS.anthropic!, refresh: async () => { throw error; } }, getAccountCredential("anthropic", id)!)).rejects.toBe(error); expect(getAccountSet("anthropic")!.accounts.find(account => account.id === id)!.needsReauth).toBeUndefined(); + expect(readOAuthRefreshIntent("anthropic", id)).toBeUndefined(); + await expect(refreshAnthropicAccountWithLock("anthropic", id, { + ...OAUTH_PROVIDERS.anthropic!, + refresh: async () => ({ access: `fresh-${index}`, refresh: `rt-fresh-${index}`, expires: Date.now() + 3600_000 }), + }, getAccountCredential("anthropic", id)!)).resolves.toBe(`fresh-${index}`); + expect(getAccountSet("anthropic")!.accounts.find(account => account.id === id)!.needsReauth).toBeUndefined(); } });