Skip to content

[Bug]: OpenCode thread wedges with "Insufficient context allowance" after delegate_task result when model window is unknown #16147

Description

@sree-akkineni

Before submitting

Area

apps/server (orchestration v2 context handoff, OpenCode adapter)

Environment

  • T3 Code Nightly 0.0.46-nightly.20261003.2610, macOS arm64
  • OpenCode 2.0.22
  • Model opencode-go/deepseek-v4.1-flash (1M context per opencode models)

Steps to reproduce

  1. Run a long OpenCode thread. Here contextUsage.usedTokens was ~581k, which is fine for a 1M model.
  2. From that thread, delegate work to Codex with delegate_task and let it finish. The result is queued as a context handoff (strategy: manual_context, status: ready).
  3. Send any message in the thread.

Expected behavior

The subagent result is delivered on the next turn (inline, or deferred/pointer if it doesn't fit), and the thread keeps working.

Actual behavior

Every turn fails with:

Provider error: Insufficient context allowance for the provider handoff. Compact the target conversation or use a larger-context model; the current request has not been truncated.

Plain messages ("Status?", "hi") fail too, so the thread is unusable until /compact is run manually. After /compact, the next turn delivered both queued handoffs inline and the thread recovered.

Likely cause (from reading the bundled server code)

  • The provider thread's contextUsage was { "usedTokens": 581117 } with no maxTokens. That means the OpenCode adapter's windowOf(cwd, model) returned undefined for this thread. readModels fills contextWindows from client.model.list with a 5s timeout and errors ignored, so a slow or failed lookup leaves the window unknown.
  • handoffBudget then falls back to a 128k window: 128k − 581k − reserve gives a budget of 0. Even a short summary handoff can't fit, so deliverContextHandoffs throws ContextHandoffBudgetError on every turn.

Suggestions

  • Make the OpenCode window lookup reliable: retry model.list, or fall back to the model's catalog limit rather than 128k for 1M-context models.
  • When the handoff budget is 0, degrade instead of failing the turn. For example, defer the handoff or deliver a t3_thread_read pointer (this already happens when coverage is too large), or show a one-click "Compact and retry" with the error.

Workaround

Run /compact in the thread. To prevent it, cap the model's limit.context (e.g. 128000) in OpenCode config so OpenCode auto-compacts before T3's fallback window is reached.

Note from the reporter

Big fan of the product and happy to be using it. I'm a non-technical user who has gotten proficient with coding agents. My Claude Code was helping me manage T3 and caught this, so take that for what it's worth.

Activity

  1. juliusmarminge commented on Oct 5, 2026

    @juliusmarminge
    Member

    Note

    Grok responding on behalf of Julius.

    Triage

    Thanks for such a thorough report, @sree-akkineni! Your reading of the bundled code was spot on, and the numbers match current main. The error and the stuck thread are the same as #15997, but the cause is different: here it's an OpenCode thread whose measured usage is past the fallback window, with a delegate_task result waiting to be delivered.

    What I found

    • When a delegate_task finishes, it writes a ready manual_context handoff onto the parent thread (Orchestrator.ts). The next turn prices it with handoffBudget. If both the stored maxTokens and the live model window are missing, that function assumes a 128k window and reserves a quarter of it (ContextHandoffBudget.ts). With usedTokens at 581117, the budget comes out to 0. A real 1M window would leave room.
    • deliverContextHandoffs then throws ContextHandoffBudgetError before injecting anything. The t3_thread_read pointer is only used when its marker fits the budget, so a 0 budget fails the turn instead of deferring. The handoff stays ready, later turns pick it up again (ProviderTurnStartService.ts), and each failed turn adds another missed-run handoff. That's why "Status?" and "hi" keep failing.
    • OpenCode only learns the window from client.model.list, with a 5 second timeout and errors ignored (OpenCode2AdapterV2.ts, readModels). The directory is marked known when the read starts, so a timeout or failed read isn't retried by readModelsOnce. Turns that fail in handoff delivery never reach the adapter, so they don't trigger the post-turn catalog retry either. The report doesn't show whether model.list timed out, errored, or omitted this model.
    • /compact defers delivery when the budget is short instead of failing, so once compaction lowers usedTokens the queued handoffs go through inline. That matches your workaround.

    Likely fix area

    • Making the OpenCode window lookup more reliable, for example by retrying a failed or timed-out model.list instead of marking the directory known up front.
    • Having handoff delivery degrade when the budget is 0 (defer it, or use a pointer) instead of failing every turn.
    • Revisiting the 128k fallback when measured usage already exceeds it.

    A maintainer will decide on the fix direction.

  2. added
    bugSomething is broken or behaving incorrectly.
    via-triageFiled through npx t3 triage
    on Oct 5, 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