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
Grep and Edit tools intermittently hang and never return on macOS #22139
The Grep and Edit tools intermittently hang after execution — the operation completes successfully (file is written, or ripgrep produces matches), but control never returns to the model. The agent gets stuck and the user must manually interrupt to continue.
Observed with both:
Grep tool — searches complete (verified by running rg via Bash with identical args and getting results), but the tool call never returns. Sometimes when interrupted, returns "No files found" even though matches exist.
Edit tool — edits are applied to disk successfully, but the tool call hangs on return. (Workaround: using sed via Bash instead.)
This is intermittent — not every call hangs. Unclear trigger, but it seems more likely to occur with larger files (~3,000+ lines).
Environment
OpenCode version: 1.4.3
OS: macOS (darwin)
Model: claude-opus-4.6 via github-copilot provider
Terminal: standard zsh
Steps to reproduce
Open a session with a large Python file (~3,700 lines) in the workspace
Use the Grep tool to search for a pattern that exists in the file, e.g.:
Grep(pattern="def.*batch", include="audit.py")
The tool hangs — no result is returned to the model. The user must interrupt.
After interruption, the result is sometimes "No files found" (incorrect) or sometimes the correct matches.
The same pattern occurs with the Edit tool:
Use Edit to replace a string in a large file
The edit is applied on disk
The tool call never returns
Expected behavior
Both Grep and Edit should return results to the model promptly after execution completes.
Workarounds
Grep: Use rg via the Bash tool instead
Edit: Use sed via the Bash tool instead
Notes
This may be related to the tool response streaming mechanism for large outputs, or a race condition in the tool completion signaling. The near-zero duration logged for some Grep calls (similar to #13353) suggests the tool may be short-circuiting or the response pipe may not be flushing correctly.
If your issue is distinct (macOS-specific, large file size trigger, affects both Grep and Edit together), it's worth keeping open, but these may have related context or fixes.
Two sequential Grep calls in the same session. First succeeds (simple literal pattern), second hangs for 4m22s until user aborts (regex with alternation |). Both target the same ~3,700-line file.
The log shows:
Permission is evaluated and granted for both calls
The successful call produces 4 message.part.updated bus events, then the session advances
The hanging call produces only 2 message.part.updated events, then 261 seconds of absolute silence — no error, no timeout, no crash — until the user aborts
The grep tool's internal execution (ripgrep spawn, stdout reading) produces zero log entries at any level, making the hang invisible from the outside. The --log-level DEBUG flag produces zero DEBUG-level lines in the log, suggesting the tool internals aren't instrumented.
This same behavior also affects the Edit and Write tools (confirmed across multiple sessions by the reporter).
The pattern with regex alternation (|) and no explicit path parameter hangs 100% of the time (2/2). The simple literal pattern with explicit path succeeds 100% (2/2).
This may narrow it down: either the regex alternation in the ripgrep args causes a stdout pipe issue, or the omission of path triggers a different code path (perhaps searching from $HOME root which is a very large tree, and ripgrep output overwhelms the pipe buffer).
In this session, the working directory is /Users/<user> (home directory). When path is omitted, the grep tool likely defaults to CWD = home, meaning ripgrep would recursively search the entire home directory for *.py files matching the pattern. That's a huge search space and could produce massive output — which might cause the stdout pipe to fill and deadlock if the consumer isn't draining it.
The successful calls specified path as a specific subdirectory, limiting the search scope.
When path is omitted, the grep tool defaults to the current working directory. In this session, CWD is $HOME. Ripgrep recursively searches the entire home directory tree, which on this machine includes large project directories, virtual environments, node_modules, media files, etc.
Even with --glob "audit.py" filtering, ripgrep must still traverse the entire directory tree to find matching filenames. On a large home directory, this traversal produces enough internal output (or takes long enough) to trigger a pipe buffer deadlock — ripgrep blocks waiting to write to stdout, while the OpenCode consumer blocks waiting for ripgrep to finish, and neither side makes progress.
Suggested fix
The grep tool should:
Default to the project root (git root or workspace root) instead of CWD when path is omitted, similar to how IDEs scope searches
Or implement a timeout on the ripgrep subprocess with a meaningful error message
Or drain the stdout pipe asynchronously to prevent buffer deadlocks regardless of output volume
Reacted by Randy Dickinson, Artur Mukhamadiev and David Schliewe
Activity
github-actions commentedon Apr 12, 2026
This issue might be a duplicate of or related to existing issues. Please check:
If your issue is distinct (macOS-specific, large file size trigger, affects both Grep and Edit together), it's worth keeping open, but these may have related context or fixes.
MattPark commentedon Apr 12, 2026
Log evidence from
--print-logsreproductionReproduced with
opencode --print-logs --log-level DEBUG(v1.4.3, macOS darwin,github-copilot/claude-opus-4.6).Full analysis posted on the related issue #17516: #17516 (comment)
Summary
Two sequential Grep calls in the same session. First succeeds (simple literal pattern), second hangs for 4m22s until user aborts (regex with alternation
|). Both target the same ~3,700-line file.The log shows:
message.part.updatedbus events, then the session advancesmessage.part.updatedevents, then 261 seconds of absolute silence — no error, no timeout, no crash — until the user abortsThe grep tool's internal execution (ripgrep spawn, stdout reading) produces zero log entries at any level, making the hang invisible from the outside. The
--log-level DEBUGflag produces zero DEBUG-level lines in the log, suggesting the tool internals aren't instrumented.This same behavior also affects the Edit and Write tools (confirmed across multiple sessions by the reporter).
MattPark commentedon Apr 12, 2026
Second reproduction — same pattern, same behavior
Reproduced the hang a second time in the same session with the identical Grep call:
Log evidence (second reproduction)
Observations so far
pathparamincludedef _run_batch_fixaudit.pydef.*batch|batch_fix|_batchaudit.pydef _run_batch_fixaudit.pydef.*batch|batch_fix|_batchaudit.pyThe pattern with regex alternation (
|) and no explicitpathparameter hangs 100% of the time (2/2). The simple literal pattern with explicitpathsucceeds 100% (2/2).This may narrow it down: either the regex alternation in the ripgrep args causes a stdout pipe issue, or the omission of
pathtriggers a different code path (perhaps searching from$HOMEroot which is a very large tree, and ripgrep output overwhelms the pipe buffer).In this session, the working directory is
/Users/<user>(home directory). Whenpathis omitted, the grep tool likely defaults to CWD = home, meaning ripgrep would recursively search the entire home directory for*.pyfiles matching the pattern. That's a huge search space and could produce massive output — which might cause the stdout pipe to fill and deadlock if the consumer isn't draining it.The successful calls specified
pathas a specific subdirectory, limiting the search scope.MattPark commentedon Apr 12, 2026
Confirmed: missing
pathparameter causes the hangSame pattern that hung twice (
def.*batch|batch_fix|_batch,include=audit.py) returns instantly when an explicitpathis provided:pathGrep(pattern="def.*batch|batch_fix|_batch", include="audit.py")$HOME)Grep(pattern="def.*batch|batch_fix|_batch", include="audit.py", path="<project_dir>")Root cause hypothesis
When
pathis omitted, the grep tool defaults to the current working directory. In this session, CWD is$HOME. Ripgrep recursively searches the entire home directory tree, which on this machine includes large project directories, virtual environments, node_modules, media files, etc.Even with
--glob "audit.py"filtering, ripgrep must still traverse the entire directory tree to find matching filenames. On a large home directory, this traversal produces enough internal output (or takes long enough) to trigger a pipe buffer deadlock — ripgrep blocks waiting to write to stdout, while the OpenCode consumer blocks waiting for ripgrep to finish, and neither side makes progress.Suggested fix
The grep tool should:
pathis omitted, similar to how IDEs scope searchesgithub-actions commentedon Jul 3, 2026
To stay organized issues are automatically closed after 60 days of no activity. If the issue is still relevant please open a new one.