Repository navigation
[BUG] Subagent final part lost — SessionProcessor.cleanup races with "removing share" (1.17.18) #36670
Description
Description
When a subagent (librarian / observer) session finishes, its final output doesn't show up in the TUI — the content just disappears. Digging into the logs, SessionProcessor.cleanup collides with the "removing share" flow when writing the final part.
The ordering is the same across all 4 affected subagent sessions:
12:34:51 created ses_… subagent session created
12:34:51 loop / process / stream step 0..5 streaming fine
12:35:21 removing share ses_… ← this deletes the session + message rows
12:35:24 ERROR FOREIGN KEY constraint failed
at Session.updatePart
at SessionProcessor.cleanup ← cleanup tries to write part, parent rows already gone
Session.updatePart does an upsert on part, whose FK points to message(id). By the time cleanup runs, the parent message (and session) rows have already been deleted by the share-removal path, so the upsert trips the FK constraint and the whole part write gets rolled back.
Net result: the subagent's last text / reasoning / step-start never lands in the DB, so the TUI has nothing to render for that turn. The DB itself is fine (PRAGMA integrity_check ok, no orphan parts / messages) — the content is just gone.
Plugins
oh-my-opencode-slim (same run also logged Plugin export is not a function for a list plugin, but the FK race reproduces independently of that
OpenCode version
1.17.18
Steps to reproduce
- Start an orchestrator session and have it dispatch subagents (librarian / observer) that run a few steps and finish normally.
- When the subagent session ends, opencode runs
removing share(deletes thesession+messagerows) and thenSessionProcessor.cleanuptries to upsert the finalpart. Session.updatePartfails withFOREIGN KEY constraint failedbecause the parentmessagerow no longer exists.- The subagent's final text / reasoning is never persisted → TUI renders nothing for that turn.
Reproduced 6 FK failures across 4 subagent sessions in a single run today, all deepseek-v4-flash, all under run e21ab353. From ~/.local/share/opencode/log/opencode.log:
level=ERROR message=process session.id=ses_0a486e447ffe… error="Failed query: insert into "part" … (cause: SQLiteError: FOREIGN KEY constraint failed)"
at Session.updatePart
at SessionProcessor.cleanup
at SessionProcessor.process
at SessionPrompt.run
Afterward, all 4 session.ids and messageIDs are missing from the DB; PRAGMA foreign_key_check returns nothing — the failed upserts were rolled back, no dirty data, just lost parts.
Screenshot and/or share link
https://opncd.ai/share/vPVSWz88
The whole terminal fills up with what looks like TypeScript source code, as if someone opened a file in vim. As soon as I drag the mouse cursor across the terminal, the screen "tears" open and the real opencode TUI shows through underneath. Resizing the window fixes it for a while, but the moment I switch to another app/window and switch back, it reverts to the broken TS-code view.
Feels like a redraw / alternate-screen-buffer issue — the TUI isn't repainting on focus regain, so stale terminal buffer content (left over from some tool output or editor) stays on screen until a mouse drag or resize forces a full repaint
Operating System
macOS 26.5.2 (25F84)
Terminal
Ghostty (xterm-ghostty)
Activity
mel0nyrame commentedon Jul 13, 2026
Dug deeper into the logs and the DB. The original report says 6 FK failures across 4 subagent sessions — the actual log shows 7 FK failures across 7 subagent sessions, all under run
e21ab353. Also the schema'sON DELETE CASCADEmakes the race worse than described.Schema: both FKs are ON DELETE CASCADE
So "removing share" only deletes the
sessionrow;messageandpartget wiped by SQLite's cascade. The original "deletes the session + message rows" is really "deletes the session row, which cascades to message and part" — and since cascade delete is atomic, the cleanup upsert is guaranteed to hit missing parent rows once it lands after the delete.7 FK failures with timing
Every one of them is the same pattern:
removing sharedeletes the session row (cascade removes message/part), thenSessionProcessor.cleanupupserts the part/message and hits the FK constraint. Gap ranges from 0.83s to 8.33s.ses_0a48e7aa…C3linsert into "part"type=textses_0a486e7d…RG0insert into "part"type=reasoningses_0a486e44…myHinsert into "part"type=textses_0a486dc1…UjAinsert into "message"(nested part step-start failure)ses_0a4855d1…m5Ninsert into "part"type=reasoningses_0a4854d8…krKinsert into "part"type=reasoningses_0a4844d8…nTeinsert into "part"type=reasoningRow 4 is an
insert into "message"failure, buterror.data.messagewraps aninsert into "part"(step-start) FK failure — the message upsert rolls back because the child part write failed. Cascaded failure.removing share — raw log (all 7)
FK error — raw log (row 1, data truncated)
All 7 share the same stack:
Session.updatePart → SessionProcessor.cleanup → SessionProcessor.process → SessionPrompt.run → SessionRunState.ensureRunning → SessionPrompt.loop.DB verification
7 failed sessions — data fully gone, no residue
All 7 messages and 7 parts are gone, wiped by cascade. The failed upserts rolled back — no half-written state.
Control group — 5 surviving subagents, data intact
ses_0a499df7b…ses_0a48f2d2e…ses_0a48f03f6…ses_0a48dcce9…ses_0a486e482…Surviving subagents kept their final output (text/reasoning/step-finish) in the part table. So the data loss is strictly tied to the "removing share" path — subagents that didn't trigger it are fine.
Parent session
This session spawned at least 12 subagents (5 surviving + 7 deleted), not 4.
Global consistency
Corrections to the original report
ses_0a486dc18…) is amessageupsert cascading from a child part failure — worth calling out separately.ON DELETE CASCADE, so "removing share" deleting one session row auto-removes message + part. Suggest rewording "deletes the session + message rows" → "deletes the session row, which cascades to message and part".mel0nyrame commentedon Jul 14, 2026
Additional screenshots:

mradwankhalil commentedon Aug 19, 2026
Follow-up from a related incident on OpenCode Desktop 1.18.18 / Windows 11 (2026-08-19). I now have a reproduction whose first symptom matches this issue: a completed subagent produced no final output, so I clicked another subagent to investigate.
Parent and child sessions
The parent was:
ses_fece7f378ffesRvg374eKUX5YC—OpenCode SQLite Database Forensic AuditIt spawned five subagents at approximately 02:08:30Z:
ses_fe8390a61ffedKDInjyU722ECz— Map phase gate surfaceses_fe8390a2dffeFLT2aHsgoa0pZa— Map LightRAG admission pathsses_fe8390992ffeyNEz37GNhMdwdV— Map production orchestrationses_fe83909dbffeNBuDAB7RoQc2zA— Research LightRAG metadata isolationses_fe8390a47ffe2Kk8HTtFpB26uV— Map claim audit toolingThe first four have normal completion evidence in SQLite and the runtime log: persisted final text, a final
step-finish,finish: stop, and cleanexiting loop/cancelentries.The fifth session,
Map claim audit tooling, is different:step-start, reasoning, several tool calls, andstep-finishfor an intermediate step.finish: tool-calls, notfinish: stop.exiting looporcancelentry for this session.02:14:48Z; the parent exited/pruned at about02:15:01Z.In other words, the session exists and its earlier work is intact, but the final answer that should have followed the last tool calls is absent. This is the same user-visible symptom described in this issue: the subagent appears to finish, but the final part is missing.
Desktop freeze immediately afterward
While investigating the completed-subagent entries in the Desktop UI, the renderer produced a burst of:
The renderer log stopped at
05:14:44.077local time. The main log was already silent since05:07:55, and there was no Electron unresponsive event, Crashpad dump, or Windows AppHang/AppCrash. The sidecar continued independently until the app was killed at approximately05:15:14.The DB remained healthy (
PRAGMA quick_check=ok, zero foreign-key violations), and the affected subagent row was not deleted. This makes the sequence look like:Important limitation
I did not find an August 19 log line for
removing share,SessionProcessor.cleanup, orFOREIGN KEY constraint failed. Therefore I cannot claim that the exact deletion race documented here is proven for this incident. The missing-final-part symptom and abnormal completion state are proven; the precise cleanup mechanism is not.Could there be a completion/cleanup path that loses the final part without emitting the FK error, or does the
removing sharerace have a variant where the failed write is rolled back before the error reaches the main log? This incident may be a useful regression case: a subagent with completed tool calls must either persist a final text/step-finish or emit an explicit terminal failure, never remain as a session ending infinish: tool-callswith no final result.This is also relevant to #42538, where the same subagent lifecycle is followed by a Desktop-wide freeze:
#42538
mradwankhalil commentedon Oct 10, 2026
The follow-up reproduction narrows this but does not yet prove the FK/share-removal race: it ends at finish: tool-calls without a final part, while the log lacks removing share, SessionProcessor.cleanup, and FK errors. Could maintainers confirm whether this is the same lifecycle failure or a separate terminal-state bug? A regression test should require every completed subagent to persist final text/step-finish or record an explicit terminal error.
thdxr commentedon Oct 11, 2026
Thanks for the report! OpenCode 2.0 is now out and development is focused on V2, so we're closing issues filed against OpenCode 1. Please upgrade (
opencode upgrade --major, details: https://anoma.ly/notes/opencode-2-0), and if this is still relevant on 2.0, reopen this issue or open a new one with your 2.0 version.— from 𝕺𝖕𝖊𝖓𝕮𝖔𝖉𝖊