fix: recover from stale Claude Code session IDs instead of retrying infinitely
When Claude Code exits with code 1 during a session resume, the group's session ID is now cleared from the database and the query is retried with a fresh session. This prevents the infinite retry loop that occurred when a stale/corrupt session ID was stored in SQLite. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -526,6 +526,10 @@ export function setSession(groupFolder: string, sessionId: string): void {
|
|||||||
).run(groupFolder, sessionId);
|
).run(groupFolder, sessionId);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function deleteSession(groupFolder: string): void {
|
||||||
|
db.prepare('DELETE FROM sessions WHERE group_folder = ?').run(groupFolder);
|
||||||
|
}
|
||||||
|
|
||||||
export function getAllSessions(): Record<string, string> {
|
export function getAllSessions(): Record<string, string> {
|
||||||
const rows = db
|
const rows = db
|
||||||
.prepare('SELECT group_folder, session_id FROM sessions')
|
.prepare('SELECT group_folder, session_id FROM sessions')
|
||||||
|
|||||||
46
src/index.ts
46
src/index.ts
@@ -30,6 +30,7 @@ import {
|
|||||||
getAllChats,
|
getAllChats,
|
||||||
getAllRegisteredGroups,
|
getAllRegisteredGroups,
|
||||||
getAllSessions,
|
getAllSessions,
|
||||||
|
deleteSession,
|
||||||
getAllTasks,
|
getAllTasks,
|
||||||
getMessagesSince,
|
getMessagesSince,
|
||||||
getNewMessages,
|
getNewMessages,
|
||||||
@@ -355,6 +356,51 @@ async function runAgent(
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (output.status === 'error') {
|
if (output.status === 'error') {
|
||||||
|
// Detect stale/corrupt session: container failed while resuming an existing session.
|
||||||
|
// Clear the session and retry once with a fresh session to avoid infinite retry loops.
|
||||||
|
if (sessionId) {
|
||||||
|
logger.warn(
|
||||||
|
{ group: group.name, staleSessionId: sessionId, error: output.error },
|
||||||
|
'Container failed with existing session — clearing stale session and retrying with fresh session',
|
||||||
|
);
|
||||||
|
delete sessions[group.folder];
|
||||||
|
deleteSession(group.folder);
|
||||||
|
|
||||||
|
const freshOutput = await runContainerAgent(
|
||||||
|
group,
|
||||||
|
{
|
||||||
|
prompt,
|
||||||
|
sessionId: undefined,
|
||||||
|
groupFolder: group.folder,
|
||||||
|
chatJid,
|
||||||
|
isMain,
|
||||||
|
assistantName: ASSISTANT_NAME,
|
||||||
|
},
|
||||||
|
(proc, containerName) =>
|
||||||
|
queue.registerProcess(chatJid, proc, containerName, group.folder),
|
||||||
|
wrappedOnOutput,
|
||||||
|
);
|
||||||
|
|
||||||
|
if (freshOutput.newSessionId) {
|
||||||
|
sessions[group.folder] = freshOutput.newSessionId;
|
||||||
|
setSession(group.folder, freshOutput.newSessionId);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (freshOutput.status === 'error') {
|
||||||
|
logger.error(
|
||||||
|
{ group: group.name, error: freshOutput.error },
|
||||||
|
'Container agent error on fresh session retry',
|
||||||
|
);
|
||||||
|
return 'error';
|
||||||
|
}
|
||||||
|
|
||||||
|
logger.info(
|
||||||
|
{ group: group.name, newSessionId: freshOutput.newSessionId },
|
||||||
|
'Fresh session retry succeeded',
|
||||||
|
);
|
||||||
|
return 'success';
|
||||||
|
}
|
||||||
|
|
||||||
logger.error(
|
logger.error(
|
||||||
{ group: group.name, error: output.error },
|
{ group: group.name, error: output.error },
|
||||||
'Container agent error',
|
'Container agent error',
|
||||||
|
|||||||
Reference in New Issue
Block a user