ugrep grep shim breaks when CLAUDE_CODE_EXECPATH is a dynamic loader (Termux glibc): '-G: cannot open shared object file', exit 127

Status Closed — duplicate
Reported on v2.1.221
Maintainer reply None cached
Activity 3 comments · opened Aug 6, 2026 · closed Aug 15, 2026

What happened

On Termux/Android, the glibc build of Claude Code is launched through the glibc
dynamic loader (ld-linux-aarch64.so.1 /path/to/claude), because Bionic cannot
exec the glibc binary directly. In that setup Claude Code sets:

CLAUDE_CODE_EXECPATH=/data/data/com.termux/files/usr/glibc/lib/ld-linux-aarch64.so.1

i.e. the loader, not the Claude binary.

The grep shell function Claude Code injects into Bash-tool shells routes greps
through its bundled ugrep:

( exec -a ugrep "$_cc_bin" -G --ignore-files --hidden -I --exclude-dir=.git ... "$@" )

with _cc_bin="${CLAUDE_CODE_EXECPATH:-}". Because _cc_bin is the loader, the
loader treats -G as the program to load and every such grep fails:

-G: error while loading shared libraries: -G: cannot open shared object file: No such file or directory

The guard above it ([[ -x $_cc_bin ]] || _cc_bin=~/.local/bin/claude, then fall
back to command grep if not executable) does not help: the loader is
executable, so the shim proceeds.

Why this is worse than a noisy error

The failure exits 127. That is non-zero, so it takes the same branch as "no
match":

cmd | grep -q pattern && do_thing    # silently behaves as "pattern absent"

So it produces false negatives in conditionals, not just visible errors.

Reproducer

# inside a Claude Code Bash tool call, on a loader-launched install
echo "$CLAUDE_CODE_EXECPATH"        # -> .../ld-linux-aarch64.so.1
echo hello | grep hello; echo "exit=$?"   # -> -G: error..., exit=127
grep hello /etc/hostname            # standalone may work if something else
                                    #    intercepts `grep` before the function

Direct confirmation that the loader is the failing component:

/data/data/com.termux/files/usr/glibc/lib/ld-linux-aarch64.so.1 -G --hidden pat file
# -> -G: error while loading shared libraries: -G: cannot open shared object file

Workaround

Force the shim's own fallback by making CLAUDE_CODE_EXECPATH non-executable,
via env in settings.json:

{ "env": { "CLAUDE_CODE_EXECPATH": "/nonexistent" } }

Then grep resolves to command grep and works normally (verified: piped
greps, grep -q conditionals and grep-to-grep pipes all exit 0).

Note ~/.bashrc is not a viable place for this fix — Bash-tool shells source a
generated snapshot, and snapshots do not carry env exports.

Suggested fix

Validate that CLAUDE_CODE_EXECPATH is the Claude executable rather than merely
-x before using it as the ugrep host — e.g. reject it when it is a dynamic
loader / when exec -a ugrep "$_cc_bin" -G --version does not succeed — and
fall back to command grep otherwise.

Environment

  • Claude Code 2.1.221 (glibc build, launched via ld.so)
  • Termux on Android, aarch64, kernel 4.14.356
  • Shell: bash (glibc), Bash tool

View original on GitHub ↗

This issue has 3 comments on GitHub. Read the full discussion on GitHub ↗