Skip to content

OpenCode v2 subagents remain running without output or surfaced errors #15581

Closed

Description

@knocking4thcylinder

OpenCode v2 subagents remain running without output or surfaced errors

Description

OpenCode v2 subagents in T3 Code can remain running / working without producing output or reporting an error. This has been observed when encountering provider rate limits: Pi reports the rate-limit errors, while OpenCode does not.

In the original incident, two OpenCode v2 subagents using opencode/mimo-v2.6-flash-free produced no output or edits for approximately 49 minutes. Both continued reporting running until manually interrupted.

A fresh test with Qwen through OpenRouter reproduced the no-output symptom for more than a minute. The rate-limit cause was not exposed in that test, so the captured result confirms the stall but does not establish its underlying cause.

Environment

  • T3 Code on Linux x86_64.
  • OpenCode v2; installed CLI reports 2.0.22 in the fresh test environment.
  • Provider instance: opencode.
  • Reproduction model: openrouter/qwen/qwen3.8-27b:free.
  • T3 Code build/version: v0.0.46-nightly.20261003.2638

Steps to reproduce

  1. In T3 Code, delegate a task through OpenCode using openrouter/qwen/qwen3.8-27b:free.

  2. Send this minimal prompt:

    Do not use tools, read files, edit anything, spawn agents, browse, or run commands.
    Immediately reply with exactly QWEN_PROBE_OK.
    
  3. Wait at least 65 seconds and inspect the delegated task's status and child history.

Observed once in the fresh test described below; frequency has not been established.

Expected behavior

The task returns the requested response, or reports an actionable provider error. If the provider is retrying after a rate limit, available retry information is surfaced rather than leaving the task silently appearing to work.

Actual behavior

After a 65-second wait, the task returned:

{
  "status": "running",
  "workState": "working",
  "summary": null,
  "waitTimedOut": true
}

At approximately 75 seconds, the child history still contained only the initial prompt, with no assistant output or error. Manual cancellation subsequently settled the task as interrupted.

Test evidence

Qwen test on October 4, 2026, UTC:

  • Requested: 02:13:39.086.
  • Started: 02:13:39.152.
  • Delegated wait timed out after 65 seconds with the task still running.
  • Inspected at approximately 02:14:54: no output or surfaced error.
  • Cancelled after inspection; terminal status confirmed as interrupted.
  • No rate-limit error appeared in the inspected OpenCode log interval.

A comparison probe using openrouter/poolside/laguna-xs-2.1:free completed normally in approximately 3.2 seconds and returned the requested response. The problem therefore did not occur with every tested model.

Separately, the user reports encountering rate limits with OpenRouter and seeing Pi report them while OpenCode does not. This comparison is user-observed; matched provider-response captures are not available.

Impact

Users and parent agents cannot tell whether a subagent is progressing, retrying, or unable to continue. Tasks can remain apparently active for extended periods without a useful explanation and require manual interruption.

Activity

  1. knocking4thcylinder commented on Oct 4, 2026

    @knocking4thcylinder
    ContributorAuthor

    Captured Qwen reproduction logs

    These are field-selected excerpts extracted from T3 Code's persisted provider protocol log, not reconstructed from recollection. Session/thread/project identifiers and unrelated conversation data are omitted. Timestamps, tool names, statuses, prompt, and results are retained.

    The records show a 65-second wait ending with the child still running, followed by a child-history inspection showing only the prompt. They also show successful manual cancellation. They establish the no-output/still-running symptom, not a provider-side rate-limit cause.

    [
      {
        "timestamp": "2026-10-04T02:13:39.064Z",
        "tool": "delegate_task",
        "phase": "started",
        "target": {
          "providerInstanceId": "opencode",
          "model": "openrouter/qwen/qwen3.8-27b:free"
        },
        "timeoutMs": 65000,
        "prompt": "Minimal provider-lifecycle reproduction test. Do not use tools, read files, edit anything, spawn agents, browse, or run commands. Immediately reply with exactly QWEN_PROBE_OK. Use only the selected free model; do not switch models or providers."
      },
      {
        "timestamp": "2026-10-04T02:14:44.128Z",
        "tool": "delegate_task",
        "result": {
          "status": "running",
          "workState": "working",
          "providerInstanceId": "opencode",
          "model": "openrouter/qwen/qwen3.8-27b:free",
          "summary": null,
          "waitTimedOut": true,
          "hasPendingChildRuns": false,
          "latestTerminalStatus": null
        }
      },
      {
        "timestamp": "2026-10-04T02:14:54.477Z",
        "tool": "t3_thread_read",
        "threadStatus": "running",
        "recentRuns": [
          {
            "status": "running",
            "requestedAt": "2026-10-04T02:13:39.086Z",
            "startedAt": "2026-10-04T02:13:39.152Z",
            "completedAt": null
          }
        ],
        "items": [
          {
            "type": "user_message",
            "status": "completed",
            "text": "Act as the test sub-agent for this task.\n\nMinimal provider-lifecycle reproduction test. Do not use tools, read files, edit anything, spawn agents, browse, or run commands. Immediately reply with exactly QWEN_PROBE_OK. Use only the selected free model; do not switch models or providers."
          }
        ],
        "hasMore": false
      },
      {
        "timestamp": "2026-10-04T02:15:04.637Z",
        "tool": "task_cancel",
        "result": {
          "status": "cancel_requested"
        }
      },
      {
        "timestamp": "2026-10-04T02:15:29.771Z",
        "tool": "task_status",
        "result": {
          "status": "interrupted",
          "workState": "result_available",
          "providerInstanceId": "opencode",
          "model": "openrouter/qwen/qwen3.8-27b:free",
          "summary": "Child task ended with status interrupted.",
          "waitTimedOut": false,
          "hasPendingChildRuns": false,
          "latestTerminalStatus": "interrupted"
        }
      }
    ]
  2. juliusmarminge commented on Oct 4, 2026

    @juliusmarminge
    Member

    Note

    Grok responding on behalf of Julius.

    Triage

    Thanks a lot for the report and the captured logs, @knocking4thcylinder. I looked into this on current main. It doesn't look like a duplicate. The long silent wait seems to come from OpenCode keeping the execution open while it retries, and T3 Code currently shows that wait as an ordinary running / working state because it drops the retry event OpenCode sends.

    What I found

    • A delegate_task child stays running / working with summary: null until its OpenCode execution ends. Heartbeats every 10–15 seconds keep the stream inside the 45-second silence timeout, so "waiting on a retry" looks the same as "working." Cancel correctly settles it as interrupted.
    • The OpenCode 2 protocol this repo pins emits a session.retry.scheduled event while the execution stays open, with the attempt number, the next retry time, and a structured error (type, message, optional HTTP status). OpenCode2AdapterV2.onTurnEvent has no case for it, so it's discarded. session.step.failed is only used for token totals and also drops its error. The turn fails only on session.execution.failed, which OpenCode doesn't send until it stops retrying.
    • Pi turns auto_retry_start into a running provider-retry error item, which is why Pi shows the rate limit and OpenCode doesn't. OpenCode 1.x has the same gap in a different form: a session.status of type retry is only marked busy, and its message isn't shown.
    • How long the retrying lasts is upstream behavior. OpenCode retries retryable 429s for a long time, including on background subagents, without failing the execution (anomalyco/opencode#44931, anomalyco/opencode#21960, anomalyco/opencode#24011).
    • The 49-minute opencode/mimo-v2.6-flash-free stall fits this path best. The roughly 65-second Qwen run is less conclusive: the OpenCode log for that interval had no rate-limit error, so it may have been first-token latency on a free model. Since the CLI under test was OpenCode 2.0.22, a changed session.retry.scheduled payload would also be skipped as undecodable on current main, with the same blank turn.

    If it's easy to grab, a redacted slice of the OpenCode event stream from the 49-minute run, plus the T3 Code version you were on, would confirm the retry event actually fired.

    Likely fix area

    One option is to handle session.retry.scheduled in the OpenCode 2 adapter the way Pi handles auto_retry_start: show a running error item with the provider message, attempt, and delay, clear it when the execution succeeds, and fail it when session.execution.failed arrives. Showing the same item on a delegated child would put it where this report was looking. Surfacing the scheduled retry wouldn't require T3 Code to invent a terminal error OpenCode hasn't sent.

    A maintainer will decide on the fix direction.

  3. added
    bugSomething is broken or behaving incorrectly.
    via-triageFiled through npx t3 triage
    on Oct 4, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething is broken or behaving incorrectly.via-triageFiled through npx t3 triage

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions