From 41562addd79d3fccf7202381c2907982281785f5 Mon Sep 17 00:00:00 2001 From: Ivan Fofanov Date: Sat, 11 Apr 2026 18:24:28 -0400 Subject: [PATCH] fix: classify "No conversation found" as session_expired Claude CLI returns "No conversation found with session ID: " when resuming an expired session. The existing error classifier checks for "conversation not found" but misses the "no conversation found" phrasing, so the session-expired recovery path (clear stale binding, retry with fresh session) never fires. This causes follow-up messages in CLI-backend conversations to fail permanently instead of transparently creating a new session. Added "no conversation found" to isCliSessionExpiredErrorMessage() alongside the existing "conversation not found" pattern. --- .../pi-embedded-helpers.isbillingerrormessage.test.ts | 6 ++++++ src/agents/pi-embedded-helpers/errors.ts | 1 + 2 files changed, 7 insertions(+) diff --git a/src/agents/pi-embedded-helpers.isbillingerrormessage.test.ts b/src/agents/pi-embedded-helpers.isbillingerrormessage.test.ts index 7dfe826e158..a78cf977729 100644 --- a/src/agents/pi-embedded-helpers.isbillingerrormessage.test.ts +++ b/src/agents/pi-embedded-helpers.isbillingerrormessage.test.ts @@ -648,6 +648,12 @@ describe("classifyFailoverReason", () => { expect(classifyFailoverReason("410 conversation expired")).toBe("session_expired"); }); + it("classifies 'No conversation found' from Claude CLI as session_expired", () => { + expect(classifyFailoverReason("No conversation found with session ID: abc123")).toBe( + "session_expired", + ); + }); + it("keeps explicit billing and auth signals on 410 text", () => { expect(classifyFailoverReason("HTTP 410: invalid_api_key")).toBe("auth"); expect(classifyFailoverReason("HTTP 410: authentication failed")).toBe("auth"); diff --git a/src/agents/pi-embedded-helpers/errors.ts b/src/agents/pi-embedded-helpers/errors.ts index e81407f6e9c..68deb227ae0 100644 --- a/src/agents/pi-embedded-helpers/errors.ts +++ b/src/agents/pi-embedded-helpers/errors.ts @@ -1109,6 +1109,7 @@ function isCliSessionExpiredErrorMessage(raw: string): boolean { lower.includes("session expired") || lower.includes("session invalid") || lower.includes("conversation not found") || + lower.includes("no conversation found") || lower.includes("conversation does not exist") || lower.includes("conversation expired") || lower.includes("conversation invalid") ||