Skip to content

Tool calls have no timeout - one unsettled tool hangs the step forever (read has no bound while grep/glob/webfetch do) #53433

Open

Description

@nathwn12

Description

An in-flight tool call that never settles hangs the step forever. The session stays busy, nothing recovers it, and only a manual session.interrupt (or a process restart) settles it. I hit this ~15 times in two hours across independent sessions.

  • packages/core/src/session/runner/step.ts:143 - Fiber.awaitAll(...) joins the tool fibers with no deadline, so one unsettled tool hangs the whole step.
  • There is no per-tool-call timeout, and no config key for one (packages/schema/src/tool.ts has no timeout field).
  • Per-tool bounds are inconsistent: grep/glob 30s (packages/core/src/filesystem.ts:70), webfetch 30s, foreground shell 120s, background shell off - and read has none at all (packages/core/src/tool/plugin/read.ts:56). Every wedge I observed was a read.
  • Recovery exists but cannot self-trigger: settleStaleToolCalls (packages/core/src/session/runner/llm.ts:329-352) runs only at drain start (llm.ts:68-69), and a stuck drain is joined rather than restarted (packages/core/src/session/run-coordinator.ts:124-134). No periodic in-process stale-tool sweep exists.

Steps to reproduce

  1. Register a plugin tool whose promise never settles (or use any tool that hangs).
  2. The step never ends; the session stays busy indefinitely.
  3. Only session.interrupt recovers it.

Observed in practice: a read call wedged mid-run and the session sat in running for 400-640 seconds. Every recovery was manual.

Plugins

@nathwn12/oc-bifrost (TUI host), oc-todo, plus one local directory plugin. No MCP servers.

OpenCode version

2.0.22 (runtime). Source reviewed: 2.0.23.

Operating System

Windows 11 Pro, build 26200 (AMD64)

Terminal

Windows Terminal (TERM=xterm-256color), PowerShell 7.6.6, bun 1.4.2

Suggested fix

  1. Give the join at step.ts:143 a per-tool, configurable deadline with a finite default.
  2. Give read the same kind of bound grep/glob already have.
  3. Run settleStaleToolCalls on a timer, not only at drain start.

Related

Activity

  1. added
    needs:complianceThis means the issue will auto-close after 2 hours.
    and removed
    needs:complianceThis means the issue will auto-close after 2 hours.
    on Oct 5, 2026
  2. github-actions commented on Oct 5, 2026

    @github-actions
    Contributor

    Thanks for updating the issue with reproduction steps and system details!

  3. kylebakerio commented on Oct 26, 2026

    @kylebakerio

    Another data point, from v1 tools (opencode 1.18.34, opencode run, local models):

    • What hung: grep called with "path": "/src", a directory that doesn't exist, outside the project. Ripgrep started from the filesystem root, never returned, and the step waited until our harness's 2 h wall-clock cap.
    • How often: twice in ~360 runs of one model, plus one other tool hang of unknown kind in ~3,800 runs.
    • How we know: the model's last request ended with finish=tool_calls, and the proxy saw nothing after that.
    • Hard to spot: --format json writes a tool part only when the tool finishes, so the transcript shows nothing pending.
    • Our workaround: we now kill rg processes older than 10 minutes from outside. The tool then returns an error and the model carries on.

    +1 for a per-tool deadline (#54503).

  4. opencodejr commented on Oct 27, 2026

    @opencodejr

    Thanks for the detailed write-up. I couldn't reproduce the stuck read here. My sandbox runs Linux, not Windows.

    What I tried, on @opencode/cli@2.0.22 with a simulated model: I had the model call read on a named pipe (FIFO) in the project that nothing writes to, which was my best guess for a read that would block forever. It didn't block. The call failed right away and the step went on.

    On the first part of the report: as far as I can tell, a tool that never settles keeping the step busy is how the code works now. There is no per-tool timeout or setting for one, so a configurable timeout would be a feature request. #51188 asks for the same thing for MCP tool calls.

    To find out why read hangs on your machine, these would help a lot:

    • The exact path arguments of the stuck read calls (for example from the session export), and whether those files were inside the project or outside it, locked by another process, or on a network or OneDrive folder.
    • Whether a permission request was waiting while the session was stuck. read can ask for permission (for example for paths outside the project), and a custom TUI host may not show that prompt, so the session would look stuck in running.
    • Whether it still happens with the default opencode TUI and without @nathwn12/oc-bifrost and oc-todo.
    • Logs from around a stuck call.

    This needs someone who can test on Windows with your setup.

    Related:

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

No labels
No labels

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions