Repository navigation
Claude thread permanently fails with "No conversation found with session ID" after fresh-session fallback resumes a newly minted id #15103
Description
Activity
Note
Grok responding on behalf of Julius.
Triage
Thanks for the detailed diagnosis, @areidyOTH! This reproduces on current
main(fed41fa88b, which includes8ed276c2). It's a real bug, and it isn't a duplicate of #2336 (closed). That one was the V1 path, where a Claude session id was resumed before the CLI had written a transcript. This one is the V2 fresh-session fallback opening a newly created id withresume.Why the replacement query uses
resumeClaudeAdapterV2.openQuerytreatsproviderTurnOrdinal > 1as proof that the native session already exists, somakeClaudeQueryOptionssendsresumeinstead ofsessionId. That's correct after an idle release of a session the CLI actually created, because reopening withsessionIdfails with "already in use".It's wrong after
ProviderTurnStartServicedropsnativeThreadRefand callsensureThread. For Claude,ensureThreadonly allocates a new session id and keeps the same provider-thread row, so the next ordinal is still above 1. The replacement query ends up asresume: <new uuid>for a conversation the CLI has never seen.Why it stays stuck
The new ref is written as
strength: "strong"beforestartTurnruns.openedNativeThreadsis only updated after a successful open, and the next turn doesn't check it anyway, because the ordinal check forcesresumeagain. Retrying can't recover the thread. As you noted, the original transcript is still under the earlier session id. Continuing that session outside T3, or starting a new thread, is the workaround for now.Where
uncertain_history_deliverycomes fromThat branch only runs when a handoff for this provider thread is still
pendingon the current native id, and it never callsresumeThread.Claude has no history injection, so text handoffs are saved as
pendingbeforestartTurnand only markedinlineonce the turn is accepted.ClaudeBackgroundWorkBlocksQueryReplacementErroris thrown inopenQuerybefore the prompt goes out, so a refused turn that had something to deliver leaves apendingmarker behind. Run 14 fits that. Run 13 failed before a provider turn was recorded, so run 14 treated it as missed history, wrote the marker, and then failed the same way. Run 15 then abandoned the live session. A later delivery rewrite onto the new native id would replace that marker, which explains why you didn't find apendingrow for the original session afterward.What needs to change
Two things:
- A newly created native id needs to be opened with
sessionId, whatever the provider-turn ordinal is. - A turn start that never reaches the CLI shouldn't leave a
pendingdelivery that later forces this fallback.
A maintainer will decide on the fix direction.
- A newly created native id needs to be opened with
- addedbugSomething is broken or behaving incorrectly.Something is broken or behaving incorrectly.via-triageFiled through npx t3 triageFiled through npx t3 triage
on Oct 3, 2026 - added 2 commits that reference this issue
on Oct 4, 2026 Hit the same on 0.0.46-nightly.20261003.2632 (Linux server, claudeAgent, claude-opus-5-5).
Sequence:
- Messages were refused by the background-work block ([Bug]: Claude refuses every message as a "model or setting change" when a thread moves between mobile and web while background work runs #15471, which this followed directly).
- The user stopped the background task.
- On the next message, T3 recorded a
provider_handoffcontext transfer and afull_thread_summarycontext handoff, set the provider thread'snativeThreadRefto a new id, and opened the Claude query withresume: <new id>. - Result:
No conversation found with session ID: <new id>(error_during_execution). Every later message resumes the same missing id, so the thread can't be used anymore. The previous native session's transcript was intact on disk.
In
openQuery,shouldResumebecomes true throughhasPersistedProviderTurn = providerTurnOrdinal > 1. That seems to count turns of the provider thread rather than of the newly created native session, so a brand-new session after a handoff is resumed instead of created.This still reproduces on
0.0.46-nightly.20261005.2667(37de6cbde65c), which includes #15770 (efecd3cf8b). It's the "rejected starts" path that #15770 left open, and the newly allocated id is still opened withresume.Sequence on macOS, claudeAgent, claude-opus-5-5, on a long thread that had an earlier context handoff:
- Run 48 wedged on an
AskUserQuestionwith a blank option description ([Bug]: Claude AskUserQuestion with a blank option description fails the run and wedges the thread #15316). - Runs 49, 50 and 51 were rejected in
ClaudeAdapterV2.startTurnwithProviderAdapterProtocolError: Claude provider turn … is still active. - I restarted the app, which also updated it to 20261005.2667, and sent a message.
- At 06:19:34.524Z, a
provider-thread.updatedevent (seq 25332) set a new native id,5f16b04e-b3bb-4952-b090-05e584cd706b, andcontext-handoff.updatedevents followed. - At 06:19:35Z, the provider log shows:
{"type":"query.close"} {"type":"query.open","options":{"model":"claude-opus-5-5[1m]","permissionMode":"bypassPermissions","resume":"5f16b04e-b3bb-4952-b090-05e584cd706b", ...}} {"type":"prompt.offer","message":{... "content":"Context handoff (full_thread_summary, delta_since_target_last_seen). 5 handoff records; ..."}} {"type":"result","subtype":"error_during_execution","duration_ms":0,"is_error":true,"num_turns":0,"session_id":"5f16b04e-b3bb-4952-b090-05e584cd706b"}The UI showed
No conversation found with session ID: 5f16b04e-…. The thread's real session (ac7ceaa1-…) is intact on disk and resumes fine withclaude --resume.So two things are still wrong on a build that includes #15770:
- The rejected starts forced a fresh session.
- The fresh id was still opened with
resumerather thansessionId.
The thread can't be used now: every message resumes the same missing id. I can share the provider event log and the
orchestration_eventsrows if that helps.- Run 48 wedged on an
Additional occurrence on macOS; installed version at investigation:
0.0.46-nightly.20261005.2667.A long-running Claude conversation stopped accepting messages after working throughout the day and overnight. Local logs show that T3 replaced a working session reference during recovery, then tried to resume the replacement before it existed. The original transcript remained on disk, but subsequent resume and fork attempts failed. Please investigate session recovery and provide a supported way to reconnect the existing conversation.
Environment
- macOS, T3 Code Nightly.
- Installed version at investigation:
0.0.46-nightly.20261005.2667. The exact build running at every earlier failure is unverified. - Claude Agent SDK with Claude Opus 5.5; the successful runtime used the 1M-context variant.
- Long-running conversation with background commands.
Observed sequence
-
Claude worked throughout the day and overnight.
-
Ordinary follow-up messages began failing with:
Claude is still running background agents or commands, and this model or setting change would end them. Wait for them to finish, or press Stop, then send the message again.
-
A history handoff was left marked as pending after a blocked message.
-
On a later message, T3 logged a fresh-session fallback with the reason
uncertain_history_delivery. -
T3 replaced the working native session reference with a newly allocated reference.
-
It closed the previous query and opened another using resume for the new reference, rather than creating the replacement session.
-
Claude returned “No conversation found with session ID: [redacted]”. The result reported zero turns, zero tokens, and zero API time.
-
Later retries reused the invalid replacement reference. Fork attempts also failed.
The original local transcript and T3 conversation history remained available. This is a failure of session continuity, not demonstrated deletion of the conversation. The survival of individual background jobs was not established.
Separate blocker when switching providers
Switching to Codex allowed replies. Switching back to Claude then produced:
Insufficient context allowance for the provider handoff. Compact the target conversation or use a larger-context model; the current request has not been truncated.
The handoff-budget calculation has not been independently reproduced, so this report does not claim that calculation is incorrect. However, it creates a recovery dead end when the target Claude session is already unavailable.
Expected behavior
- A message rejected before delivery should not leave history state that unnecessarily abandons a valid session.
- A newly allocated session must be created before it can be resumed.
- An unsuccessful replacement must not permanently displace the last working session reference.
- Resume and fork failures should offer a supported recovery action, without manual database edits.
- Context-allowance failures should provide an actionable compaction or concise-handoff recovery path.
Evidence and limits
Local provider logs, server traces, and read-only database inspection support the sequence above. The server explicitly recorded an uncertain-history-delivery fallback, followed by a resume request for the replacement session and a missing-session response. The exact internal reason the creation-versus-resume decision selected resume has not been reproduced.
No app, session, or database files were changed during diagnosis. This report contains no work titles, project names, account identifiers, session/thread IDs, transcript excerpts, local paths, or private-work screenshots.
Prepared by Codex (GPT-6-Astra), using local read-only investigation; posted with the user’s authorization.
What happened
A long-running Claude thread (created via the T3 MCP
t3_thread_*tools and driven by an orchestrator thread) suddenly started failing every turn with:That session ID never existed. The thread's real Claude session (
9b7e437e-…) had been running for ~4 hours and its transcript is still intact in~/.claude/projects/<worktree>/9b7e437e-….jsonl. The thread is now permanently stuck: every new message fails the same way.Diagnosis
Sequence from
server.trace.ndjson, the per-thread provider event log, andstatev2.sqlite(times UTC):sessionId: 9b7e437e-…; ~6,700 events of normal work follow, all withsession_id: 9b7e437e-…. The agent starts a long-running background shell.message.dispatchturns (runs 13, 14;t3_thread_sendwithmode: autothenmode: queue) fail inClaudeAdapterV2.startTurnwithClaudeBackgroundWorkBlocksQueryReplacementError("Claude is still running background agents or commands…"). This is the guard inClaudeAdapterV2.tsopenQuery(~L6836–6843).task_notification); T3 dispatches aprovider-continuationturn (run 15).ProviderTurnStartServicelogsProvider resume failed; attempting a fresh native sessionwithreason: "uncertain_history_delivery"(ProviderTurnStartService.ts~L658–704). It never callsresumeThread; it fails fast because some context handoff to this provider thread hasdelivery.status === "pending"for the current native id, most likely left behind by the refused runs 13/14 (I could not confirm this from the DB). It then callsensureThreadwithexistingProviderThread: { ...providerThread, nativeThreadRef: null }, which mints a fresh native id13aeed5e-….resume: "13aeed5e-…"rather thansessionId: "13aeed5e-…". The CLI answers immediately withresult/error_during_execution,errors: ["No conversation found with session ID: 13aeed5e-…"]. Runs 16 and 17 repeat this.Root cause of step 5, in
ClaudeAdapterV2.tsopenQuery(~L6861–6878 at8ed276c2; L6887–6889 on currentmain):providerTurnOrdinal > 1is used as proof that the native session exists. But after the fresh-session fallback inProviderTurnStartService, the provider thread keeps its turn history while getting a brand-new native id. So the adapter passesresumefor a session the CLI has never seen. The fallback can never work for any thread with more than one provider turn.Resulting persistent state:
orchestration_v2_projection_provider_threads.payload_json.nativeThreadRef={ driver: "claudeAgent", nativeId: "13aeed5e-…", strength: "strong" }, so all later turns resume the non-existent id. Twocontext_handoffsrows (full_thread_summaryfor run 15, anddelta_since_target_last_seen) were written withdelivery.nativeThreadId: 13aeed5e-…, but the history never reached Claude.Possible directions (not tested):
openQueryusessessionId, notresume, for a newly minted native id regardless ofproviderTurnOrdinal.nativeThreadRefasstronguntil the CLI confirms the session.ClaudeBackgroundWorkBlocksQueryReplacementErrorprobably shouldn't leave apendinghandoff delivery that later forces the fresh-session path.Steps to reproduce
Not reproduced deterministically; reconstructed from logs:
claudeAgent) thread and run several turns, soproviderTurnOrdinal > 1.until …; do sleep; donewaiter run in the background).t3_thread_send). It is refused with "Claude is still running background agents or commands…". Sending a second one inqueuemode is also refused.Provider resume failed; attempting a fresh native session(uncertain_history_delivery) in the trace, followed byquery.openwithresume: <new uuid>andNo conversation found with session ID: <new uuid>. Every later turn on the thread fails the same way.A more direct check of the core bug: force the fallback path in
ProviderTurnStartService(e.g. makeresumeThreadfail) on a Claude thread with ≥2 provider turns, and observe that the replacement query is opened withresumefor the freshly minted id.Version
Desktop AppImage 0.0.46-nightly.20261003.2610 (commit 8ed276c). Same code is present on
mainas of 2026-10-03.Environment
Linux x64 (kernel 7.0.0), Node v26.8.2, Claude Code CLI 2.1.288, desktop app (server.mode: desktop, 127.0.0.1:3773)
Evidence
Related issues
#2336 (closed): a thread becomes permanently unusable because T3 resumes a Claude session id that has no transcript (V1
resume_cursor_json, CLI killed before first write). Same symptom and the same "permanently stuck" outcome, but a different code path. This one is the V2ProviderTurnStartServicefresh-session fallback combined withClaudeAdapterV2decidingresumefromproviderTurnOrdinal > 1.Fix applied or workaround
Nothing was changed on the machine. Workaround: the original conversation is intact, so it can be continued outside T3 with
claude --resume <original session id>in the thread's worktree, or the work can be handed to a new T3 thread. The stuck thread itself cannot recover without editingstatev2.sqlite.Filed by
Claude Code (claude-opus-5-5) via
t3 triage