You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Aborted provider stream recorded as clean stop (finish=unknown, zero usage, no text) — subagent returns empty with no error #37852
When a provider stream terminates mid-generation without a finish reason or usage chunk, opencode records the assistant message with finish=unknown, zero tokens, and no text part, then exits the agent loop as if the turn completed normally. No error is logged or surfaced.
For a subagent this means the parent receives an empty task result with no error signal — it cannot distinguish "provider dropped the stream" from "agent finished with nothing to say."
Observed on 1.18.3 with a subagent on fireworks-ai/accounts/fireworks/models/deepseek-v4-flash: 6 healthy tool-call turns, then a ~34.5s stream that emitted ~15.8 KB of reasoning and simply ended — no text, zero recorded usage, finish=unknown, nothing in the logs. The loop exited cleanly and the parent's task tool returned an empty <task_result>.
Expected: a stream that ends without a finish reason (or with zero content and zero usage) is treated as an error and retried — or at minimum surfaced as a distinct truncated finish state so callers can react (e.g. a subagent's parent retrying or failing the task explicitly).
If your issue is specifically about the provider dropping the stream (rather than a timeout/task tool behavior), it may be a distinct root cause worth tracking separately. Please review #32132 and comment there or close this one if it matches your situation.
Reviewed #32132 — related symptom family, but a distinct root cause; this one is worth tracking separately.
#32132 (per the confirmed forensics in its comments): a streaming tool execution (bash) is aborted mid-flight; the child DB row records Tool execution aborted, and the parent sees completed with empty/partial output. The failure happens while a tool runs, and an abort is recorded somewhere.
This issue: no tool is in flight. The provider stream itself ends mid-generation — after reasoning deltas, before any text/tool call, and before the finish/usage chunk. opencode then persists the assistant message with finish=unknown, zero usage, zero content, and no error recorded anywhere, and the loop exits as if the turn completed. The parent's task result is completely empty, not partial.
Different failure point (stream finalization vs. tool-execution abort propagation) and a different signature (finish=unknown + zero usage + zero tokens vs. Tool execution aborted in the child). The requested fix here is narrower: a stream that ends without a finish reason (or with zero content and zero usage) should be treated as an error/retry, or surfaced as a distinct truncated finish state.
The assistant message contained no text or completed tool call. The runtime log showed the stream starting and the loop then exiting normally, with no provider error or retry. Sending another message started a fresh turn.
The 1.18.8 loop still treats this terminal finish="unknown" state as a completed turn.
Reacted by Lorenzo Drudi, Giancarlo Sorrentino, Valentin Lemaire, gmas05, pbas-bs, Federico Leonardi, fbia-bendingspoons, Pietro De Nicolao, Ennio Nasca, Mar Badia and 4 more
I'm seeing a closely related failure mode on 1.18.4+ with a custom Anthropic provider (deepseek-v4-pro):
The stream drops during or before a tool_use in a subagent. Unlike #37852 where the loop exits cleanly with finish=unknown, in my case opencode enters the tool execution state and the subagent hangs with MessageAbortedError ("Tool execution aborted") for 5–53 minutes. The message row still shows {input: 0, output: 0} — i.e. opencode never received any response tokens from the stream.
Key observations from opencode.db:
100% reproducible from 1.18.4 onward (1.18.3 occasionally succeeded), also present on 1.18.8 and 1.18.9.
Main-agent tool calls in the same session are unaffected; only subagent tool execution is affected.
Intermittent within the same parent session: retrying the same subagent task often succeeds immediately. This rules out a session-global state corruption.
Highly concentrated in long-lived parent sessions with heavy tool usage, but session size alone is not sufficient — another parent with 5000+ messages had zero failures.
macOS 15.7.7, Node v24.13.1, Anthropic protocol via custom provider.
The finish=unknown / zero-token pattern described here and the Tool execution aborted pattern I'm hitting both point to the same root cause: the provider stream terminates silently and opencode's stream handler does not recover or retry. The difference is just when the drop occurs — before a tool_use (→ empty turn) vs. during one (→ hung tool execution).
Confirmed independently on OpenCode 1.18.9, Linux, using a custom OpenAI-compatible provider (@ai-sdk/openai) and a general subagent inheriting the primary model.
The child session completed several normal turns first. Its last healthy assistant turn had finish="tool-calls" with non-zero usage and completed read/glob calls. The next persisted assistant message was:
That terminal message had no text part and no completed tool call. The agent loop then logged exiting loop; the parent task received no structured failure indicating that the delegated work was incomplete.
Relevant controls checked:
general.steps = null
general.maxSteps = null
no request timeout configured
the child was only a few agentic iterations into the task
OpenCode was already at the latest release (1.18.9)
A useful SQLite diagnostic for affected sessions is:
SELECT
json_extract(data, '$.finish') AS finish,
json_extract(data, '$.tokens.input') AS input_tokens,
json_extract(data, '$.tokens.output') AS output_tokens,
json_extract(data, '$.time.completed') AS completed_at
FROM message
WHERE session_id ='<child-session-id>'ORDER BY time_created DESCLIMIT1;
This returned unknown | 0 | 0 | <timestamp> for the interrupted child. Other child sessions under the same parent completed normally, so this is not a configured step ceiling or a parent-session-wide stop condition.
The actionable issue is the lifecycle contract: finish="unknown" plus zero usage/content must not be converted into a successful/empty task result. It should either resume/retry the child or propagate an explicit interrupted/error result to the parent so orchestration can recover.
Ciao @rekram1-node! I have #39473 that likely fix it, and I've already tested it with ~10 candidates, who reported it solves their issue. LMK if I can help in any way :)
Yeah I've seen this issue too with subagents with deepseek v4 flash that they finish midstream with a "length" reason, and that the agent / subagent "completes" which is incorrect, it should resume instead.
This appeared to set the output token max from 32k to 128k and now deepseek v4 preview new max agents in subagents don't stall out on writing 32k tokens in reasoning and then "exit" mid stream.
Reacted by hajimi9527, Number16BusShelter and Arunprasath Rajendran
There was another PR taht fixed this by having it retry the "length" error code instead which is the deepseek v4 flash new error code for the output exceeds the length which is also a terminal state instead of a resumable / retry state in the subagent ( or maybe even main agent )
Another independent confirmation of this exact signature, in interactive TUI mode (not subagents), across 3 incidents in ~26 hours (opencode 1.18.13–1.18.15, Linux, provider opencode-go / model deepseek-v4-flash, ai-sdk runtime).
Symptom matches this issue precisely: a step emits its reasoning part (a few seconds), then step-finish records reason:"unknown" with tokens.output: 0 and no text/tool-call part follows. The TUI waits indefinitely; nothing appears in the runtime log at any level (no WARN/ERROR around the stall timestamps). The session only recovers by exiting and resuming with opencode -s <session> — the same context then continues normally (the very next step finishes with tool-calls and non-zero output), which proves the local session state was intact and the loss happens at the provider request boundary.
Part-level records from the local opencode.db (part table), times UTC:
{
"environment": {
"opencode": "1.18.13-1.18.15 (TUI, interactive mode)",
"os": "linux",
"provider": "opencode-go",
"model": "deepseek-v4-flash",
"llm_runtime": "ai-sdk",
"agent_mode": "build (primary session, not subagent)"
},
"symptom": "A step produces a reasoning part (a few seconds long), then step-finish records reason=\"unknown\" with tokens.output=0 and no text/tool-call part follows. The TUI waits indefinitely. No error is logged at any level. The session only recovers by exiting and resuming with `opencode -s <session>`; the same context then continues normally (next step finishes with tool-calls and non-zero output), proving local session state was intact and the loss is at the provider request boundary.",
"frequency": "3 incidents in ~26 hours across three independent long-running interactive sessions.",
"incidents": [
{
"label": "Incident A: 2026-08-08 ~02:50-02:55 UTC",
"parts": [
{
"utc": "2026-08-08T02:49:33Z",
"type": "step-start",
"reason": null,
"output_tokens": null,
"text": null
},
{
"utc": "2026-08-08T02:49:34Z",
"type": "step-finish",
"reason": "tool-calls",
"output_tokens": 114,
"text": null
},
{
"utc": "2026-08-08T02:49:49Z",
"type": "step-start",
"reason": null,
"output_tokens": null,
"text": null
},
{
"utc": "2026-08-08T02:49:49Z",
"type": "reasoning",
"reason": null,
"output_tokens": null,
"text": "`applyResearch` ALWAYS increments actionsTaken (+1) \u2014 even when the research is the arms_race free research (legal past the 2-action budget)"
},
{
"utc": "2026-08-08T02:50:18Z",
"type": "step-finish",
"reason": "tool-calls",
"output_tokens": 380,
"text": null
},
{
"utc": "2026-08-08T02:50:49Z",
"type": "step-start",
"reason": null,
"output_tokens": null,
"text": null
},
{
"utc": "2026-08-08T02:50:49Z",
"type": "reasoning",
"reason": null,
"output_tokens": null,
"text": "\"Choose a project to build\"\u2014 3 eligible"
},
{
"utc": "2026-08-08T02:53:07Z",
"type": "step-finish",
"reason": "unknown",
"output_tokens": 0,
"text": null
}
]
},
{
"label": "Incident B: 2026-08-09 ~05:18-05:24 UTC",
"parts": [
{
"utc": "2026-08-09T05:47:48Z",
"type": "step-start",
"reason": null,
"output_tokens": null,
"text": null
},
{
"utc": "2026-08-09T05:47:48Z",
"type": "reasoning",
"reason": null,
"output_tokens": null,
"text": "There's `debug_goToState`, `debug_setupState` (money 50, 5 hand cards), `debug_addResources`, `debug_dumpState`, `debug_playOneMove` (zombie"
},
{
"utc": "2026-08-09T05:47:57Z",
"type": "step-finish",
"reason": "tool-calls",
"output_tokens": 100,
"text": null
},
{
"utc": "2026-08-09T05:48:00Z",
"type": "step-start",
"reason": null,
"output_tokens": null,
"text": null
},
{
"utc": "2026-08-09T05:48:01Z",
"type": "reasoning",
"reason": null,
"output_tokens": null,
"text": "The debug panel is a notification/state log \u2014 no action invocation buttons. The BGA Studio dev interface: in the running table, there's a me"
},
{
"utc": "2026-08-09T05:48:14Z",
"type": "step-finish",
"reason": "tool-calls",
"output_tokens": 64,
"text": null
},
{
"utc": "2026-08-09T05:48:17Z",
"type": "step-start",
"reason": null,
"output_tokens": null,
"text": null
},
{
"utc": "2026-08-09T05:48:18Z",
"type": "step-finish",
"reason": "tool-calls",
"output_tokens": 33,
"text": null
}
]
},
{
"label": "Incident C: 2026-08-09 ~09:48-09:55 UTC",
"parts": [
{
"utc": "2026-08-09T09:59:21Z",
"type": "step-start",
"reason": null,
"output_tokens": null,
"text": null
},
{
"utc": "2026-08-09T09:59:23Z",
"type": "reasoning",
"reason": null,
"output_tokens": null,
"text": "Interesting. Now I understand the model. The lab level VP stars: the standalone engine grants VP when a lab level becomes active (vpDelta fr"
},
{
"utc": "2026-08-09T09:59:31Z",
"type": "step-finish",
"reason": "tool-calls",
"output_tokens": 146,
"text": null
},
{
"utc": "2026-08-09T09:59:37Z",
"type": "step-start",
"reason": null,
"output_tokens": null,
"text": null
},
{
"utc": "2026-08-09T09:59:39Z",
"type": "reasoning",
"reason": null,
"output_tokens": null,
"text": "Now I understand the lab VP star model:\n\n1. The lab level VP star (LAB_LEVELS vp: l3=1, l4=1, l5=1, l6=2, l7=3) is granted when the level be"
},
{
"utc": "2026-08-09T09:59:50Z",
"type": "step-finish",
"reason": "tool-calls",
"output_tokens": 148,
"text": null
},
{
"utc": "2026-08-09T09:59:57Z",
"type": "step-start",
"reason": null,
"output_tokens": null,
"text": null
},
{
"utc": "2026-08-09T09:59:58Z",
"type": "reasoning",
"reason": null,
"output_tokens": null,
"text": "Now I understand the lab VP model. Looking at the standalone: the lab level VP is granted when the level becomes active (vpDelta). The curre"
}
]
}
],
"local_evidence_source": "opencode.db `part` table (step-start/step-finish/reasoning rows) and ~/.local/share/opencode/log/opencode.log (stream records show providerID=opencode-go, llm.runtime=ai-sdk; no WARN/ERROR lines at the stall timestamps)."
}
Related observation for the maintainers: the stall is silent end-to-end — no error event, no log line, no retry — so operators have no signal until the session visibly stops producing. A chunk timeout with a visible error/retry (as #37580/#39968 suggest) would convert these into recoverable blips.
Confirming same behavior in Qwen3.7 using Kimi K3 as a subagent.
@Raynos fix export OPENCODE_EXPERIMENTAL_OUTPUT_TOKEN_MAX=131072 does not seem to work.
Errors are not present in logs, only " loop exit with orphaned interrupted tool" warning is visible.
There was substantial reasoning content in that step, so this is not an entirely empty model response.
After this, opencode run exited and the session stopped progressing. There was no active OpenCode process left.
This seems particularly relevant to #41469 / #41466: that proposed retry checks for finish === "unknown" only when no text/reasoning/tool output was produced. In this case, reasoning output was produced before the provider stream terminated, so I don't think that condition would catch this failure.
I can provide a sanitized opencode export of the affected session if useful.
Reproduced the same silent-stop with a LiteLLM proxy returning 402 terminal_quota_exhausted for quota-exhausted providers (Alibaba Token Plan, OpenCode Go, Z.AI).
Environment
opencode 1.18.18
LiteLLM proxy v1.97.0 (Docker) with custom_callbacks.py that transforms quota-exhaustion 429s into 402 terminal_quota_exhausted
oh-my-openagent 4.19.4 (npm latest) with runtime_fallback hook
Live evidence
Session ses_fea3bf10bffelWmR3Za9oHPf23 (Sisyphus ultraworker, 5.8M input tokens) spawned subagents on glm-5.2 / minimax-m3 during Token Plan weekly quota exhaustion (before 2026-08-19 19:53 UTC reset).
Event DB shows:
message.updated with role: assistant, modelID: glm-5.2 — no error.name, no error.data
Zero message.part.updated events with assistant text/tool content follow
Session lifetime: 684ms–2s (directly stale)
No MessageAbortedError recorded (unlike the omo internal-abort path which DOES write it)
This matches the silent-clean-stop path: provider stream terminates mid-generation (quota exhausted → 402 → stream ends without finish reason/usage), opencode records finish=unknown, zero tokens, no text, exits the agent loop normally. Parent subagent gets empty result with no error signal.
Key distinction: two separate stale mechanisms
omo internal abort path (MessageAbortedError IS written): omo's runtime_fallback hook aborts via abortSessionRequest(), opencode records MessageAbortedError. This is noisy but visible. Fix: oh-my-openagent PR Better Permission Always for specific patterns #6764 (merged to dev 2026-08-18, not in 4.19.4 release).
The silent-clean-stop is particularly dangerous for subagent workflows: the parent agent receives an empty task result with no error signal, cannot distinguish "provider dropped" from "agent finished with nothing to say," and may proceed as if the subagent completed successfully.
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.
Activity
github-actions commentedon Jul 20, 2026
This issue might be a duplicate of existing issues. Please check:
If your issue is specifically about the provider dropping the stream (rather than a timeout/task tool behavior), it may be a distinct root cause worth tracking separately. Please review #32132 and comment there or close this one if it matches your situation.
fernanDOTdo commentedon Jul 20, 2026
Reviewed #32132 — related symptom family, but a distinct root cause; this one is worth tracking separately.
#32132 (per the confirmed forensics in its comments): a streaming tool execution (bash) is aborted mid-flight; the child DB row records
Tool execution aborted, and the parent seescompletedwith empty/partial output. The failure happens while a tool runs, and an abort is recorded somewhere.This issue: no tool is in flight. The provider stream itself ends mid-generation — after reasoning deltas, before any text/tool call, and before the finish/usage chunk. opencode then persists the assistant message with
finish=unknown, zero usage, zero content, and no error recorded anywhere, and the loop exits as if the turn completed. The parent's task result is completely empty, not partial.Different failure point (stream finalization vs. tool-execution abort propagation) and a different signature (
finish=unknown+ zero usage + zero tokens vs.Tool execution abortedin the child). The requested fix here is narrower: a stream that ends without a finish reason (or with zero content and zero usage) should be treated as an error/retry, or surfaced as a distincttruncatedfinish state.Davide95 commentedon Jul 28, 2026
I observed several turns using
openai/gpt-5.6-solwhere OpenCode recorded:The assistant message contained no text or completed tool call. The runtime log showed the stream starting and the loop then exiting normally, with no provider error or retry. Sending another message started a fresh turn.
The 1.18.8 loop still treats this terminal finish="unknown" state as a completed turn.
Maizify commentedon Jul 29, 2026
#39456
I'm seeing a closely related failure mode on 1.18.4+ with a custom Anthropic provider (deepseek-v4-pro):
The stream drops during or before a tool_use in a subagent. Unlike #37852 where the loop exits cleanly with finish=unknown, in my case opencode enters the tool execution state and the subagent hangs with MessageAbortedError ("Tool execution aborted") for 5–53 minutes. The message row still shows {input: 0, output: 0} — i.e. opencode never received any response tokens from the stream.
Key observations from opencode.db:
100% reproducible from 1.18.4 onward (1.18.3 occasionally succeeded), also present on 1.18.8 and 1.18.9.
Main-agent tool calls in the same session are unaffected; only subagent tool execution is affected.
Intermittent within the same parent session: retrying the same subagent task often succeeds immediately. This rules out a session-global state corruption.
Highly concentrated in long-lived parent sessions with heavy tool usage, but session size alone is not sufficient — another parent with 5000+ messages had zero failures.
macOS 15.7.7, Node v24.13.1, Anthropic protocol via custom provider.
The finish=unknown / zero-token pattern described here and the Tool execution aborted pattern I'm hitting both point to the same root cause: the provider stream terminates silently and opencode's stream handler does not recover or retry. The difference is just when the drop occurs — before a tool_use (→ empty turn) vs. during one (→ hung tool execution).
abigaha commentedon Jul 29, 2026
Confirmed independently on OpenCode 1.18.9, Linux, using a custom OpenAI-compatible provider (
@ai-sdk/openai) and ageneralsubagent inheriting the primary model.The child session completed several normal turns first. Its last healthy assistant turn had
finish="tool-calls"with non-zero usage and completed read/glob calls. The next persisted assistant message was:{ "finish": "unknown", "tokens": { "input": 0, "output": 0, "reasoning": 0, "cache": { "read": 0, "write": 0 } } }That terminal message had no text part and no completed tool call. The agent loop then logged
exiting loop; the parent task received no structured failure indicating that the delegated work was incomplete.Relevant controls checked:
general.steps = nullgeneral.maxSteps = null1.18.9)A useful SQLite diagnostic for affected sessions is:
This returned
unknown | 0 | 0 | <timestamp>for the interrupted child. Other child sessions under the same parent completed normally, so this is not a configured step ceiling or a parent-session-wide stop condition.The actionable issue is the lifecycle contract:
finish="unknown"plus zero usage/content must not be converted into a successful/empty task result. It should either resume/retry the child or propagate an explicit interrupted/error result to the parent so orchestration can recover.Davide95 commentedon Aug 5, 2026
Ciao @rekram1-node! I have #39473 that likely fix it, and I've already tested it with ~10 candidates, who reported it solves their issue. LMK if I can help in any way :)
Raynos commentedon Aug 5, 2026
Yeah I've seen this issue too with subagents with deepseek v4 flash that they finish midstream with a "length" reason, and that the agent / subagent "completes" which is incorrect, it should resume instead.
rekram1-node commentedon Aug 6, 2026
Will look ty
Raynos commentedon Aug 6, 2026
The workaround for me locally was Raynos/dotfiles@bd6aab7
This appeared to set the output token max from 32k to 128k and now deepseek v4 preview new max agents in subagents don't stall out on writing 32k tokens in reasoning and then "exit" mid stream.
Raynos commentedon Aug 6, 2026
There was another PR taht fixed this by having it retry the "length" error code instead which is the deepseek v4 flash new error code for the output exceeds the length which is also a terminal state instead of a resumable / retry state in the subagent ( or maybe even main agent )
rekram1-node commentedon Aug 6, 2026
This issue specifically is about missing finish / final parts of a stream, the issue you are discussing is separate
voilamochu commentedon Aug 9, 2026
Another independent confirmation of this exact signature, in interactive TUI mode (not subagents), across 3 incidents in ~26 hours (opencode 1.18.13–1.18.15, Linux, provider
opencode-go/ modeldeepseek-v4-flash, ai-sdk runtime).Symptom matches this issue precisely: a step emits its reasoning part (a few seconds), then
step-finishrecordsreason:"unknown"withtokens.output: 0and no text/tool-call part follows. The TUI waits indefinitely; nothing appears in the runtime log at any level (no WARN/ERROR around the stall timestamps). The session only recovers by exiting and resuming withopencode -s <session>— the same context then continues normally (the very next step finishes withtool-callsand non-zero output), which proves the local session state was intact and the loss happens at the provider request boundary.Part-level records from the local
opencode.db(parttable), times UTC:{ "environment": { "opencode": "1.18.13-1.18.15 (TUI, interactive mode)", "os": "linux", "provider": "opencode-go", "model": "deepseek-v4-flash", "llm_runtime": "ai-sdk", "agent_mode": "build (primary session, not subagent)" }, "symptom": "A step produces a reasoning part (a few seconds long), then step-finish records reason=\"unknown\" with tokens.output=0 and no text/tool-call part follows. The TUI waits indefinitely. No error is logged at any level. The session only recovers by exiting and resuming with `opencode -s <session>`; the same context then continues normally (next step finishes with tool-calls and non-zero output), proving local session state was intact and the loss is at the provider request boundary.", "frequency": "3 incidents in ~26 hours across three independent long-running interactive sessions.", "incidents": [ { "label": "Incident A: 2026-08-08 ~02:50-02:55 UTC", "parts": [ { "utc": "2026-08-08T02:49:33Z", "type": "step-start", "reason": null, "output_tokens": null, "text": null }, { "utc": "2026-08-08T02:49:34Z", "type": "step-finish", "reason": "tool-calls", "output_tokens": 114, "text": null }, { "utc": "2026-08-08T02:49:49Z", "type": "step-start", "reason": null, "output_tokens": null, "text": null }, { "utc": "2026-08-08T02:49:49Z", "type": "reasoning", "reason": null, "output_tokens": null, "text": "`applyResearch` ALWAYS increments actionsTaken (+1) \u2014 even when the research is the arms_race free research (legal past the 2-action budget)" }, { "utc": "2026-08-08T02:50:18Z", "type": "step-finish", "reason": "tool-calls", "output_tokens": 380, "text": null }, { "utc": "2026-08-08T02:50:49Z", "type": "step-start", "reason": null, "output_tokens": null, "text": null }, { "utc": "2026-08-08T02:50:49Z", "type": "reasoning", "reason": null, "output_tokens": null, "text": "\"Choose a project to build\" \u2014 3 eligible" }, { "utc": "2026-08-08T02:53:07Z", "type": "step-finish", "reason": "unknown", "output_tokens": 0, "text": null } ] }, { "label": "Incident B: 2026-08-09 ~05:18-05:24 UTC", "parts": [ { "utc": "2026-08-09T05:47:48Z", "type": "step-start", "reason": null, "output_tokens": null, "text": null }, { "utc": "2026-08-09T05:47:48Z", "type": "reasoning", "reason": null, "output_tokens": null, "text": "There's `debug_goToState`, `debug_setupState` (money 50, 5 hand cards), `debug_addResources`, `debug_dumpState`, `debug_playOneMove` (zombie" }, { "utc": "2026-08-09T05:47:57Z", "type": "step-finish", "reason": "tool-calls", "output_tokens": 100, "text": null }, { "utc": "2026-08-09T05:48:00Z", "type": "step-start", "reason": null, "output_tokens": null, "text": null }, { "utc": "2026-08-09T05:48:01Z", "type": "reasoning", "reason": null, "output_tokens": null, "text": "The debug panel is a notification/state log \u2014 no action invocation buttons. The BGA Studio dev interface: in the running table, there's a me" }, { "utc": "2026-08-09T05:48:14Z", "type": "step-finish", "reason": "tool-calls", "output_tokens": 64, "text": null }, { "utc": "2026-08-09T05:48:17Z", "type": "step-start", "reason": null, "output_tokens": null, "text": null }, { "utc": "2026-08-09T05:48:18Z", "type": "step-finish", "reason": "tool-calls", "output_tokens": 33, "text": null } ] }, { "label": "Incident C: 2026-08-09 ~09:48-09:55 UTC", "parts": [ { "utc": "2026-08-09T09:59:21Z", "type": "step-start", "reason": null, "output_tokens": null, "text": null }, { "utc": "2026-08-09T09:59:23Z", "type": "reasoning", "reason": null, "output_tokens": null, "text": "Interesting. Now I understand the model. The lab level VP stars: the standalone engine grants VP when a lab level becomes active (vpDelta fr" }, { "utc": "2026-08-09T09:59:31Z", "type": "step-finish", "reason": "tool-calls", "output_tokens": 146, "text": null }, { "utc": "2026-08-09T09:59:37Z", "type": "step-start", "reason": null, "output_tokens": null, "text": null }, { "utc": "2026-08-09T09:59:39Z", "type": "reasoning", "reason": null, "output_tokens": null, "text": "Now I understand the lab VP star model:\n\n1. The lab level VP star (LAB_LEVELS vp: l3=1, l4=1, l5=1, l6=2, l7=3) is granted when the level be" }, { "utc": "2026-08-09T09:59:50Z", "type": "step-finish", "reason": "tool-calls", "output_tokens": 148, "text": null }, { "utc": "2026-08-09T09:59:57Z", "type": "step-start", "reason": null, "output_tokens": null, "text": null }, { "utc": "2026-08-09T09:59:58Z", "type": "reasoning", "reason": null, "output_tokens": null, "text": "Now I understand the lab VP model. Looking at the standalone: the lab level VP is granted when the level becomes active (vpDelta). The curre" } ] } ], "local_evidence_source": "opencode.db `part` table (step-start/step-finish/reasoning rows) and ~/.local/share/opencode/log/opencode.log (stream records show providerID=opencode-go, llm.runtime=ai-sdk; no WARN/ERROR lines at the stall timestamps)." }Related observation for the maintainers: the stall is silent end-to-end — no error event, no log line, no retry — so operators have no signal until the session visibly stops producing. A chunk timeout with a visible error/retry (as #37580/#39968 suggest) would convert these into recoverable blips.
dengyakui commentedon Aug 10, 2026
Same problem. The subagent was stopped quietly, and jobs return empty result. and retry many times.
Number16BusShelter commentedon Aug 10, 2026
Confirming same behavior in Qwen3.7 using Kimi K3 as a subagent.
@Raynos fix
export OPENCODE_EXPERIMENTAL_OUTPUT_TOKEN_MAX=131072does not seem to work.Errors are not present in logs, only " loop exit with orphaned interrupted tool" warning is visible.
Opencode version: 1.18.16
OS: OSX
Model Provider: Alibaba
SDK: OpenAPI Compatible
weixiang1862 commentedon Aug 11, 2026
Same problem. opencode-go provider, deepseek-v4-flash model.
John-Ferrel commentedon Aug 11, 2026
I hit what looks like the same failure mode on OpenCode 1.18.15, but through the
opencode-goprovider rather than Fireworks.Environment:
1.18.15opencode-godeepseek-v4-flashopencode run --format json --session ...by cc-connect.The turn had already completed multiple tool calls successfully. The previous step ended normally with:
{ "reason": "tool-calls", "tokens": { "total": 138102, "input": 52, "output": 578, "cache": { "read": 137472 } } }OpenCode then started another assistant step and generated about 19 seconds of reasoning. The reasoning stopped abruptly in the middle of a sentence.
The persisted assistant message ended as:
{ "finish": "unknown", "tokens": { "input": 0, "output": 0, "reasoning": 0, "cache": { "write": 0, "read": 0 } } }and the final part was:
{ "type": "step-finish", "reason": "unknown", "tokens": { "input": 0, "output": 0, "reasoning": 0 } }There was substantial reasoning content in that step, so this is not an entirely empty model response.
After this,
opencode runexited and the session stopped progressing. There was no active OpenCode process left.This seems particularly relevant to #41469 / #41466: that proposed retry checks for
finish === "unknown"only when no text/reasoning/tool output was produced. In this case, reasoning output was produced before the provider stream terminated, so I don't think that condition would catch this failure.I can provide a sanitized
opencode exportof the affected session if useful.dengyakui commentedon Aug 11, 2026
empty rate 4/9
dengyakui commentedon Aug 11, 2026
opencode v2 also has the problem.
niStee commentedon Aug 19, 2026
Additional reproduction: LiteLLM proxy 402 terminal_quota_exhausted
Reproduced the same silent-stop with a LiteLLM proxy returning
402 terminal_quota_exhaustedfor quota-exhausted providers (Alibaba Token Plan, OpenCode Go, Z.AI).Environment
terminal_quota_exhaustedLive evidence
Session
ses_fea3bf10bffelWmR3Za9oHPf23(Sisyphus ultraworker, 5.8M input tokens) spawned subagents onglm-5.2/minimax-m3during Token Plan weekly quota exhaustion (before 2026-08-19 19:53 UTC reset).Event DB shows:
message.updatedwithrole: assistant,modelID: glm-5.2— no error.name, no error.datamessage.part.updatedevents with assistant text/tool content followMessageAbortedErrorrecorded (unlike the omo internal-abort path which DOES write it)This matches the silent-clean-stop path: provider stream terminates mid-generation (quota exhausted → 402 → stream ends without finish reason/usage), opencode records
finish=unknown, zero tokens, no text, exits the agent loop normally. Parent subagent gets empty result with no error signal.Key distinction: two separate stale mechanisms
omo internal abort path (MessageAbortedError IS written): omo's runtime_fallback hook aborts via
abortSessionRequest(), opencode recordsMessageAbortedError. This is noisy but visible. Fix: oh-my-openagent PR Better Permission Always for specific patterns #6764 (merged to dev 2026-08-18, not in 4.19.4 release).opencode silent-clean-stop path (NO error written): provider stream ends without finish reason, opencode exits agent loop as normal completion. This is the path described in this issue (Aborted provider stream recorded as clean stop (finish=unknown, zero usage, no text) — subagent returns empty with no error #37852) and Session silently stops on empty LLM response (finish: unknown, 0 tokens) #41469. No omo-side fix can detect this because opencode reports it as a clean stop, not an error.
Impact
The silent-clean-stop is particularly dangerous for subagent workflows: the parent agent receives an empty task result with no error signal, cannot distinguish "provider dropped" from "agent finished with nothing to say," and may proceed as if the subagent completed successfully.
Related
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 𝕺𝖕𝖊𝖓𝕮𝖔𝖉𝖊