[BUG] argv[0]-based find/grep/rg dispatch fails in amd64 containers on Apple Silicon
Preflight Checklist
- [x] I have searched existing issues and this hasn't been reported yet
- [x] This is a single bug report (please file separate reports for different bugs)
- [x] I am using the latest version of Claude Code
What's Wrong?
Related to #84639 — same shim, same injected -G, different cause. That issue's proposed fix
would cover this one too.
The find/grep/rg shell functions route through the embedded bfs/ugrep/ripgrep by
identifying themselves via argv[0]:
( exec -a ugrep "$_cc_bin" -G --ignore-files --hidden -I --exclude-dir=.git ... "$@" )
Inside an amd64 container on Apple Silicon, a caller-chosen argv[0] never reaches the
process — the Rosetta 2 binfmt_misc registration lacks the P (preserve-argv[0]) flag, so the
kernel discards it at interpreter hand-off. The arguments then hit the ordinary CLI option parser:
! grep -n foo somefile → error: unknown option '-G'
! find . -name '*.md' → error: unknown option '-S'
(! = run in Claude Code's own shell. In the user's plain terminal the same commands work, because
that shell does not source the snapshot — which is part of what makes this confusing to diagnose.)
Grep/Glob are absent from the tool list at the same time, which is intended — the v2.1.117
changelog replaces them with "embedded bfs and ugrep available through the Bash tool". That
premise fails here, so every default search path is dead at once; nothing works until the agent
is told to use /usr/bin/grep.
envp is not rewritten by the kernel, so the ARGV0 environment-variable channel — which the
binary already accepts, and which the shim's own msys/cygwin branch already uses — still works.
Native platforms are unaffected: on macOS the shim's zsh branch works end-to-end.
What Should Happen?
grep and find inside Claude Code's shell should reach the embedded ugrep/bfs and return
results, as they do on a native host:
! grep -n 'pattern' somefile → matching lines (currently: error: unknown option '-G')
! find . -name '*.md' → matching paths (currently: error: unknown option '-S')
grep --version is the quickest way to see whether dispatch fired — it prints ugrep 7.5.0 ... on
a native host and 2.1.224 (Claude Code) here — but that is the diagnostic, not the goal. The goal
is that searches work.
Two independent asks:
- **The shim should reach the embedded binaries whether or not a caller-chosen
argv[0]
survives.** #84639 proposes verifying dispatch (exec -a ugrep "$_cc_bin" -G --version) and
falling back to command grep otherwise — that covers this case and causes nobody has hit yet.
A narrower alternative that keeps the embedded tools working is in Additional Information.
- If the shim cannot reach the embedded binaries,
Grep/Globshould not be removed. Not a
request to undo v2.1.117 — the changelog conditions that swap on the binaries being available
through the Bash tool, and here they are not. This can ship without touching the shim.
Also worth noting: claude doctor reports Search: OK (bundled) in this state. Having that check
actually invoke one of the binaries would make this class of failure a one-line diagnostic.
Error Messages/Logs
All of these are run inside Claude Code's own shell (`!` prefix). The same commands succeed in a
plain terminal, which does not source the snapshot.
! grep -n 'pattern' somefile
error: unknown option '-G'
! find . -name '*.md'
error: unknown option '-S'
! grep --version
2.1.224 (Claude Code) # expected: ugrep 7.5.0 ...
`-G` and `-S` are injected by the shim, not typed by the user.
Steps to Reproduce
Requires an Apple Silicon Mac running an amd64 container (ours: Rancher Desktop, VZ +
Rosetta 2).
1. Does this affect you? (30 s, no Claude Code needed)
docker run --rm -it --platform linux/amd64 rockylinux:9 bash
dnf install -y nodejs
echo 'console.log(process.argv0)' > a.js
( exec -a aaa node a.js )
- prints
/usr/bin/node→ affected, continue - prints
aaa→ not affected; nothing below will reproduce
That probe is the authoritative check — it measures the precondition directly. For context on why,
inspect your emulation handler on the VM that runs your containers (inside the container that
directory exists but is empty):
cat /proc/sys/fs/binfmt_misc/*
Ours reads interpreter /mnt/lima-rosetta/rosetta / flags: OCF — no P (preserve-argv[0]). Per
the kernel docs that is what discards the caller's argv[0], so we'd expect a handler registered
with P not to hit this; we have not verified that, since we have no P-flagged handler to test
against. Use the probe, not the flags, to decide whether you are affected.
The same command with --platform linux/arm64 on the same machine prints aaa.
2. The bug, in two commands. Install Claude Code in that container:
CC=$(readlink -f "$(command -v claude)")
( exec -a ugrep "$CC" --version ) # 2.1.224 (Claude Code) <-- argv[0] channel: dead
ARGV0=ugrep "$CC" --version # ugrep 7.5.0 ... <-- env-var channel: works
The binary accepts both identity channels; only the argv[0] one is dead here.
3. The symptom. Start Claude Code without --allowedTools Grep,Glob (with that flag the
shim is not installed and the bug does not appear):
! type -t grep # function
! grep --version # 2.1.224 (Claude Code) <-- expected: ugrep 7.5.0 ...
! grep -n foo somefile
# error: unknown option '-G'
Grep/Glob are absent from the tool list in that session, so there is no fallback.
Claude Model
Opus
Is this a regression?
No, this never worked
Last Working Version
_No response_
Claude Code Version
2.1.224 (Claude Code)
Platform
Anthropic API
Operating System
Other Linux
Terminal/Shell
VS Code integrated terminal
Additional Information
_No response_
This issue has 1 comment on GitHub. Read the full discussion on GitHub ↗