Skip to content

read tool hangs indefinitely on /mnt/... (WSL Windows mount) paths — no error, no timeout, bash tool works on same path #28849

@MekaretEriker

Description

@MekaretEriker

Summary

The read tool hangs indefinitely with no error, no timeout, no retry when the file path is on a Windows mount (/mnt/c/..., /mnt/d/..., etc.) under WSL. Same path works flawlessly via the bash tool (cat, head). The session stays in busy status forever until manually aborted.

OS-level access to the same files is instant (time cat /mnt/c/.../file.md → ~16 ms). So the I/O itself is not the cause — the issue is inside the read tool implementation.

Environment

  • OS: Windows 11 + WSL2 Ubuntu
  • OpenCode: 1.14.50 (Linux x86-64 binary at ~/.opencode/bin/opencode)
  • Provider/Model: tested with OpenRouter deepseek/deepseek-v4-pro AND deepseek/deepseek-v4-flash — same hang for both
  • Agent: build
  • Project directory: /home/mekaret/relkhon-vault (WSL native filesystem)

Reproduction matrix

Model File path target Tool requested Result
deepseek-v4-flash /home/mekaret/.../file.md (WSL native) read ✅ completes in ~3 s
deepseek-v4-pro /home/mekaret/.../file.md (WSL native) read ✅ completes in ~3 s
deepseek-v4-flash /mnt/c/Users/.../file.md (Windows mount) read ❌ hangs indefinitely (180s+, never returns)
deepseek-v4-pro /mnt/c/Users/.../file.md (Windows mount) read ❌ hangs indefinitely (180s+, never returns)
deepseek-v4-flash /mnt/c/Users/.../file.md bash (head -1) ✅ completes in ~1 s

So the model and the tool-call streaming format are not the issue (other tool calls work in the same session shape). The read tool itself, on /mnt/... paths, never completes.

Log signature

On a working session (/home/ path, read tool):

INFO  service=session id=<sid> directory=/home/mekaret/relkhon-vault created
INFO  service=session.prompt session.id=<sid> step=0 loop
INFO  service=session.processor session.id=<sid> messageID=<mid> process
INFO  service=llm providerID=openrouter modelID=deepseek/deepseek-v4-flash session.id=<sid> agent=build mode=primary stream
INFO  service=session.prompt session.id=<sid> step=1 loop          ← tool result came back
INFO  service=session.processor session.id=<sid> messageID=<mid2> process
INFO  service=llm ... stream
INFO  service=session.prompt session.id=<sid> step=2 loop
INFO  service=session.prompt session.id=<sid> exiting loop          ← clean completion

On a stuck session (/mnt/c/ path, read tool):

INFO  service=session id=<sid> directory=/home/mekaret/relkhon-vault created
INFO  service=session.prompt session.id=<sid> step=0 loop
INFO  service=session.processor session.id=<sid> messageID=<mid> process
INFO  service=llm providerID=openrouter modelID=deepseek/deepseek-v4-pro session.id=<sid> agent=build mode=primary stream
                                                                    ← session.prompt step=1 NEVER FIRES
                                                                    ← no further log entries on this sessionID until manual abort
INFO  (~3 min later, manual abort) service=session.prompt session.id=<sid> cancel
ERROR service=session.processor session.id=<sid> error=Aborted process

Inspecting the assistant message via the session API shows the model does produce reasoning + a streaming tool call in state.status: "running", but the call never finalizes. No step=1 event is ever emitted by the prompt loop.

What rules this out

  • Not an I/O / mount issue: direct cat /mnt/c/.../file.md from WSL completes in ~16 ms. The file is fully readable from the WSL side.
  • Not a model issue: same model on /home/ works fine; same /mnt/c/ path hangs across multiple models.
  • Not a path resolution issue: opencode_path_get directory=/home/... returns the expected WSL path. The user prompt contains the path as a literal string — no rewriting happens before the model sees it.
  • Not a permission issue: file is rwxrwxrwx for the running user.
  • Not a tool-call streaming issue: the bash tool works on the same /mnt/c/ path within seconds.

Hypothesis

Something in the read tool implementation does extra processing on the path before serving the file. That extra step blocks on /mnt/... paths but not on /home/.... Candidates I can't verify from the outside (binary is compiled):

  1. A "stay within project directory" guard that does a realpath walk and gets stuck (e.g. WSL's realpath on /mnt/c/... triggers something pathological).
  2. An fs.watch / fs.stat cache that races on cross-filesystem paths.
  3. A symlink-resolution loop that hangs on the DrvFs layer.
  4. An asynchronous file-read using a streaming primitive that is silently dropped on /mnt/... paths.

The fact that the hang is silent (no error, no log line, no timeout) is the most actionable signal: there's no error handler being hit, which suggests an await that never resolves rather than a thrown exception that's swallowed.

Proposed acceptance criteria

  • The read tool either completes on /mnt/... paths within a reasonable time, or fails with a clear error (e.g. "path outside project directory: refusing for safety, use bash if you need it").
  • In all cases, the read tool emits a step=1 event on the session prompt loop within a configurable timeout (default 30 s), so a hang surfaces as TIMEOUT instead of an indefinite busy.
  • At the very least, a clear log line on tool entry/exit so the hang location is debuggable from the server log.

Workaround

Instruct the agent to use the bash tool (cat, head) instead of read for any file outside the project directory. This works but is clunky to enforce in agent prompts — the model defaults to read for file inspection.

Related but distinct

  • #16991 — visibility / permissions / git worktree on /mnt/. Different surface; my issue is specifically the read tool hang.
  • #6460 — early read/shell failures with wrong path on new WSL session. Different mechanism; my issue is reproducible on long-running, healthy sessions.
  • #16596 — symlink-targeted WSL folders hang. Possibly related root cause (symlink resolution) but my project directory is plain /home/mekaret/relkhon-vault with no symlink involvement.

Happy to provide additional traces, full server log excerpts, or run targeted strace if useful.

Metadata

Metadata

Assignees

Labels

No labels
No labels

Type

No type
No fields configured for issues without a type.

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions