From 2e473cde00dc8872e827f7a169d23709e40349f6 Mon Sep 17 00:00:00 2001 From: Eddy Date: Mon, 20 Apr 2026 17:16:35 +0200 Subject: [PATCH] fix: stale Claude-Session-ID automatisch resetten [appimage] MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Wenn die in SQLite gespeicherte claude_session_id keine passende Konversation mehr hat (neue Maschine, Cache geleert, frische Installation), warf das SDK "No conversation found with session ID: " und der Chat blieb kaputt — der Retry in claude-bridge.js hat NIE gegriffen, weil er auf queryOptions.sessionId geprueft hat waehrend wir queryOptions.resume setzen. Fix: - claude-bridge.js: Retry-Guard auf queryOptions.resume umgezogen + Match auf die konkrete Fehlermeldung ("No conversation found with session ID"). Bei stale ID: session-reset-Event an Rust senden, dann retry ohne resume. - claude.rs: Neuer Handler fuer session-reset — loescht die stale claude_session_id aus der aktiven Session in der DB, damit die App beim naechsten Start nicht wieder in denselben Fehler laeuft. Reproduziert auf VM + NixOS-Desktop nach frischer Installation. Co-Authored-By: Claude Opus 4.7 (1M context) --- scripts/claude-bridge.js | 20 ++++++++++++++------ src-tauri/src/claude.rs | 19 +++++++++++++++++++ 2 files changed, 33 insertions(+), 6 deletions(-) diff --git a/scripts/claude-bridge.js b/scripts/claude-bridge.js index cefdb13..7233556 100644 --- a/scripts/claude-bridge.js +++ b/scripts/claude-bridge.js @@ -481,18 +481,26 @@ async function sendMessage(message, requestId, model = null, contextOverride = n }); } - // Hilfsfunktion: Iteration mit Fallback bei ungueltiger Session-ID + // Hilfsfunktion: Iteration mit Fallback bei ungueltiger Session-ID. + // Typischer Auslöser: "No conversation found with session ID: " + // passiert wenn die in SQLite gespeicherte Claude-Session lokal fehlt + // (neue Maschine, Projekt-Cache geloescht, frische Installation, ...). async function* iterateWithRetry() { try { for await (const ev of conversation) yield ev; } catch (err) { - // Wenn Resume-Session ungueltig → Retry ohne sessionId - if (queryOptions.sessionId) { + const msg = err?.message || String(err); + const isStaleSession = /no conversation found with session id/i.test(msg); + if (queryOptions.resume && isStaleSession) { + const staleId = queryOptions.resume; + // Rust-Seite informieren, damit die stale ID aus der DB geloescht + // wird — sonst probieren wir beim naechsten Start wieder dasselbe. + sendEvent('session-reset', { staleSessionId: staleId, reason: msg }); sendMonitorEvent('agent', 'Resume fehlgeschlagen, starte neue Session', { - reason: err.message || String(err), - oldSessionId: queryOptions.sessionId, + reason: msg, + oldSessionId: staleId, }); - delete queryOptions.sessionId; + delete queryOptions.resume; conversation = query({ prompt: fullPrompt, options: queryOptions }); for await (const ev of conversation) yield ev; } else { diff --git a/src-tauri/src/claude.rs b/src-tauri/src/claude.rs index bdd8a96..44d5df4 100644 --- a/src-tauri/src/claude.rs +++ b/src-tauri/src/claude.rs @@ -256,6 +256,25 @@ fn handle_bridge_message(app: &AppHandle, msg: BridgeMessage) { } let _ = app.emit("claude-result", &payload); } + "session-reset" => { + // Bridge meldet: resume-Session war ungueltig ("No conversation + // found with session ID"). Stale claude_session_id aus DB + // entfernen, sonst laeuft die App beim naechsten Start wieder + // in denselben Fehler. + if let Some(db_state) = app.try_state::>>() { + let db_lock = db_state.lock().unwrap(); + if let Ok(Some(active_id)) = db_lock.get_setting("active_session_id") { + if !active_id.is_empty() { + if let Ok(Some(mut session)) = db_lock.get_session(&active_id) { + let old = session.claude_session_id.take(); + let _ = db_lock.update_session(&session); + println!("🧹 Stale claude_session_id geloescht: {:?}", old); + } + } + } + } + let _ = app.emit("session-reset", &payload); + } "all-stopped" => { println!("⏹️ Alle Agents gestoppt"); let _ = app.emit("all-stopped", ());