From 3769df3096ff105806b495445c714a44a9472c36 Mon Sep 17 00:00:00 2001 From: xiwuqi Date: Wed, 18 Mar 2026 16:22:50 -0500 Subject: [PATCH] fix: classify invalid-model fallback errors --- src/agents/failover-error.test.ts | 20 ++++++++++++++++++++ src/agents/model-fallback.test.ts | 27 +++++++++++++++++++++++++++ 2 files changed, 47 insertions(+) diff --git a/src/agents/failover-error.test.ts b/src/agents/failover-error.test.ts index e5f2b6633f4..a4db5e56b10 100644 --- a/src/agents/failover-error.test.ts +++ b/src/agents/failover-error.test.ts @@ -334,6 +334,26 @@ describe("failover-error", () => { ).toEqual({ kind: "context_overflow" }); }); + it("treats invalid-model HTTP 400 payloads as model_not_found instead of format", () => { + expect( + resolveFailoverReasonFromError({ + message: "openrouter/__invalid_test_model__ is not a valid model ID", + }), + ).toBe("model_not_found"); + expect( + resolveFailoverReasonFromError({ + status: 400, + message: "HTTP 400: openrouter/__invalid_test_model__ is not a valid model ID", + }), + ).toBe("model_not_found"); + expect( + resolveFailoverReasonFromError({ + status: 422, + message: "invalid model: openrouter/__invalid_test_model__", + }), + ).toBe("model_not_found"); + }); + it("treats HTTP 422 as format error", () => { expect( resolveFailoverReasonFromError({ diff --git a/src/agents/model-fallback.test.ts b/src/agents/model-fallback.test.ts index e2141e518c9..7420423d489 100644 --- a/src/agents/model-fallback.test.ts +++ b/src/agents/model-fallback.test.ts @@ -591,6 +591,33 @@ describe("runWithModelFallback", () => { expect(run.mock.calls[1]?.[1]).toBe("gpt-4.1-mini"); }); + it("records invalid-model HTTP 400 responses as model_not_found during fallback", async () => { + const cfg = makeCfg(); + const run = vi + .fn() + .mockRejectedValueOnce( + Object.assign( + new Error("HTTP 400: openrouter/__invalid_test_model__ is not a valid model ID"), + { status: 400 }, + ), + ) + .mockResolvedValueOnce("ok"); + + const result = await runWithModelFallback({ + cfg, + provider: "openrouter", + model: "__invalid_test_model__", + run, + }); + + expect(result.result).toBe("ok"); + expect(run).toHaveBeenCalledTimes(2); + expect(result.attempts).toHaveLength(1); + expect(result.attempts[0]?.reason).toBe("model_not_found"); + expect(run.mock.calls[1]?.[0]).toBe("openai"); + expect(run.mock.calls[1]?.[1]).toBe("gpt-4.1-mini"); + }); + it("warns when falling back due to model_not_found", async () => { setLoggerOverride({ level: "silent", consoleLevel: "warn" }); const warnSpy = vi.spyOn(console, "warn").mockImplementation(() => {});