Repository navigation
Description
Summary
In opencode v2.1.4, a subagent call can complete successfully — the child session is recorded with idle_outcome: succeeded, a real output-token count and cost — while the parent receives an empty result body (Subagent completed without a text response.). The child's work and report are lost to the parent, and nothing indicates the result was dropped rather than never produced.
Environment
- opencode version: v2.1.4
- OS: Linux 6.18.54.1-microsoft-standard-WSL2 (linux x64)
- Terminal: TERM=xterm-256color
- Shell: /bin/bash
- Install/channel: latest (release)
- Active plugins: none found in config
Reproduction
- In a parent session, launch a subagent that performs a long research/QA task and writes a final prose report (observed with a custom read-only QA subagent,
mode: subagent, modelopencode-go/glm-5.3-flash#high). - Let the subagent finish on its own (no interruption, no compaction in the parent).
- Observe the parent tool result:
Subagent completed without a text response. - Inspect the child session's row in
opencode.db(session_v2): it showsidle_outcome = succeeded,tokens_output ≈ 10k, a non-zero cost, andresume_attempts = 0.
Expected Behavior
The parent receives the subagent's final text. If the result genuinely cannot be delivered, the tool result should say so with a diagnostic (e.g. "child completed but its final message could not be read"), not an empty success body.
Actual Behavior
Subagent completed without a text response. — indistinguishable from a subagent that produced nothing. Two consecutive runs in the same session behaved this way (both QA subagents, ~24 min and ~34 min wall-clock, 10k and 25k output tokens recorded); the other subagents in the same session returned text normally during the same period.
Consequence: a full QA pass was performed, paid for, and discarded; the parent had to re-verify by hand and merge without the QA record.
Additional Context
- Child session evidence (from
~/.local/share/opencode/opencode.db, read-only):
title <redacted: long QA re-verification>
agent <custom QA subagent>
duration 24.3 min
idle_outcome succeeded
tokens_output 10139
cost $0.10
resume_attempts 0
- Related: Sub-agent Task silently returns empty result when the final response stream fails (e.g. 503) — no error, no retry, completed work lost #40527 (final response stream fails → empty result), Aborted provider stream recorded as clean stop (finish=unknown, zero usage, no text) — subagent returns empty with no error #37852 (aborted stream recorded as clean stop). This case differs in that
idle_outcomeissucceededand substantial output tokens were recorded, so it looks like delivery/persistence between child completion and parent tool result rather than a failed stream. Task tool can drop a completed subagent result after persistence #48626 described the same shape on v1.18.30 and was closed as not planned; this is a v2 report with the session-row evidence. - Workaround: none found from the parent side. Re-running the subagent wastes the work; the child's report is not readable through the
subagenttool.
Activity
opencode-agent commentedon Oct 25, 2026
Thanks for the detailed report and the session-row evidence.
In v2.1.4 the parent gets
Subagent completed without a text response.in two cases:idle_outcome = succeededwith ~10k output tokens fits both, so we need to see the child's messages to tell them apart. Could you share, from the sameopencode.db(read-only, with prompts and file contents redacted as before), the child session's last 3–5assistantmessages, with:text,reasoning,tool, …) and whether thetextparts are emptyfinish/rawFinishand the output tokens for each messageYou can reply here or edit the issue. If you edit it, please also leave a short comment saying you've updated it, so we know you're done.
Related issues, ordered by likelihood, though none looks like an exact match:
finish:"error"/MALFORMED_FUNCTION_CALLwith empty content is reported to the parent as a successful completion #52378: same parent message, but the child's last message hadfinish:"error"with empty content and 0 tokenscompletedwith empty outputabarita commentedon Oct 25, 2026
Thanks — that narrowing is useful, and the child data answers it. I inspected the child sessions in
opencode.db(read-only; no prompts, file contents or task text are included below, only part types/counts/finish/tokens).Case A — child whose parent got the empty result (QA task, 2 h run earlier the same day)
Last four
assistantmessages in order:tool-calls/tool_callsreasoning(5,335 ch),tooltool-calls/tool_callsreasoning(381 ch),text(66 ch)stop/stopidlesucceededSo the latest error-free assistant message has zero content parts. The findings it had produced lived in the earlier messages (290/299), and the final message is empty. That is your case 1, in the sharper form "last message has no parts at all" rather than "text part is empty".
Case B — the other empty parent result (longer run, same day)
tool-calls/tool_callstooltool-calls/tool_callstoolstop/stopreasoning(8,020 ch),text(114 ch)idlesucceededHere the last message does have a text part, but it is a 114-character preamble that announces the next action and ends with a colon — the model stopped mid-plan (
finish: stop) right after saying what it was about to do. The substantive report is in the finalreasoningpart, not intext. So "which message holds the report?" — in Case A, an earlier assistant message; in Case B, none in text at all.The other two answers
stop/succeededwith real token usage.What would have made these debuggable from the parent side
The parent receives
Subagent completed without a text response.in both cases, which is indistinguishable from "the child did nothing". Two cheap improvements:textpart in the child's history (any message, not only the last) before giving up, since in Case A the answer existed two messages earlier.child finished (stop) with no text parts; last message had reasoning only (8.0k ch) — its result may be in reasoning. That alone would have saved the first investigation.Happy to pull anything else from the session rows if it helps pin the delivery path.
Dante-dan commentedon Oct 25, 2026
I traced Case A to the result selector: it stops at the latest completed, error-free assistant message even when that message has no text. I prepared a focused fix that selects the last such message containing nonempty text, shared by normal completion and restart recovery. The normal path also searches beyond its previous 20-message limit.
Reference: Dante-dan/opencode@44fc9d2...e311d9e
The existing subagent tool, lifetime, and session execution suites pass: 49 tests. Core typecheck and the repository pre-push
bun run checkalso pass (34 successful tasks).This recovers available text in Case A; it cannot recover the substantive report in Case B, where that report exists only in reasoning. The final 114-character text would still be returned. Reasoning stays excluded from the parent result.
cep207 commentedon Oct 27, 2026
We see the same "empty result accepted as success" acceptance pattern in the main agent path on Desktop 2.1.4 / CLI core 1.19.4 (
opencode-go,glm-5.3-flash/mimo-v2.6-flash): an assistant step withcontent: []andfinish: "stop"right after a tool result ends the turn asidle / succeeded, no output, no error, no retry. Frequency from local DB: 3 silent stops / ~625 assistant messages over 2 days. Full JSON sample and log analysis in #55378 — probably one shared guard (reject an empty assistant step after a tool result, or retry it once) can fix both this and the subagent variant.opencodejr commentedon Oct 28, 2026
Thanks for the detailed report and the session-row evidence.
One detail would tell us which problem this is. The parent's result is built only from the text parts of the child session's last assistant message. If that final message has no text part (only reasoning, only tool calls, or an empty
contentarray), the parent getsSubagent completed without a text response.. The child can still showidle_outcome = succeededand real token and cost totals from its earlier steps in that case.Could you check the last assistant message of one affected child session in
opencode.db(read-only, for examplesqlite3 -readonly) and share, with prompts and file contents redacted:contentpart types (for examplereasoning,text,tool) and whether anytextpart is non-emptyfinishandrawFinishvalues and its output-token countIf that last message does contain the report text, the result really was lost on the way to the parent, and we'll look into that. If it doesn't, this is most likely one of the existing issues below.
You can reply here with the details, or edit the issue. If you edit it, please also leave a comment saying you've updated it so we know you're done.
Possibly related issues, ordered by likelihood:
finish: "stop") is treated as a successful turn. session: empty assistant response (content=[], finish=stop) ends turn silently as succeeded #59518 reported this withopencode-goglm-5.3-flash, the model you used.finish:"error"/MALFORMED_FUNCTION_CALLwith empty content is reported to the parent as a successful completion #52378: a subagent whose last message has an error orlengthfinish and no text is reported to the parent as completed with this same message.succeededwith many output tokens, but its final turn has no text.completedresult, but triggered by a missing job entry or a failed final stream.cep207 commentedon Oct 29, 2026
Additional test from my side (Windows Desktop 2.1.4 / CLI core 1.19.4), controlled A/B on subagent result delivery:
Case A — subagent explicitly instructed to end its final turn on a tool call with NO text response:
/home/robert/...), not artifacts of the workspace globbed.Case B (control) — same task with a final prose summary: normal result, as expected.
Interpretation: on Windows/1.19.x the empty drop from this report doesn't reproduce (selector falls back to non-empty parts). Suggests the v2.1.4 Case A regression is platform/build-specific — and separately, the fallback behavior (feeding tool echoes to the parent as a "result" from an apparently unrelated context) may be its own delivery defect worth a guard.
opencodejr commentedon Oct 31, 2026
We're closing this for now because we haven't heard back. To tell whether this is a new bug, we need to know what the child session's last assistant message contained: its
contentpart types, itsfinish/rawFinishvalues, and whether there was any non-emptytextpart. Without that, we can't tell whether the report was lost on the way to the parent or whether the child's final step simply produced no text.If the final message did contain the report text, please reply with those details (redacted) and we can reopen this. If it had no text, the cause is most likely one of these, so please follow them instead:
finish: "stop") is treated as a successful turn. It has also been seen withopencode-goglm-5.3-flash.finish:"error"/MALFORMED_FUNCTION_CALLwith empty content is reported to the parent as a successful completion #52378: an error orlengthfinish with no text is reported to the parent as completed.Thanks again for the detailed report.