[BUG] Bash output renderer dumps Ink scrollback source when grep -n returns non-contiguous matches (v2.1.119, Agent Teams)
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?
Claude Code CLI crashes inside the Ink render layer when the Bash tool returns output from grep -n that matches a pattern on non-contiguous line numbers within a single file. Instead of rendering the snippet block cleanly, the TUI flushes the minified source of the snippet renderer function itself (ig_, scrolledOffAbove/Below buffers, Br6, vw9) into the visible output. An uncaught exception inside createInstance follows.
The same renderer function is observed leaking in a second, different trigger path (long cat | head -N output with a cd induced Shell cwd was reset notice), suggesting the root cause is inside ig_() — the scrollback snippet renderer — and the Bash output formatter reaches it through multiple code paths.
What Should Happen?
Observed output (sanitized)
The rendered tool-result block starts correctly — three matches on non-contiguous lines are shown with correct line numbers and the surrounding method signature text as produced by grep -n.
Then, where an ellipsis / gap indicator should appear, the TUI instead flushes the minified source of its own renderer into the visible output:
A=0;A<H.scrolledOffAbove.length;A++)Br6($,H.scrolledOffAbove[A],H.scrolledOffAboveSW[A]);
for(let A=K.row;A<=O.row;A++){let z=A===K.row?K.col:0,Y=A===O.row?O.col:_.width-1;
Br6($,vw9(_,A,z,Y),T[A]>0)}
for(let A=0;A<H.scrolledOffBelow.length;A++)Br6($,H.scrolledOffBelow[A],H.scrolledOffBelowSW[A]);
return $.join(`
...
503 `)}function ig_(H,_,q,K,O){let T=Zq_(H);if(!T||q>K)return;
let{start:$,end:A}=T,z=Math.max(q,$.row),Y=Math.min(K,A.row);if(z>Y)return;
let{width:w,softWrap:D}=_,j=[],f=[];
for(let J=z;J<=Y;J++){let M=J===$.row?$.col:0,P=J===A.row?A.col:w-1;
j.push(vw9(_,J,M,P)),f.push(D[J]>0)}
if(O==="above"){if(H.scrolledOffAbove.push(...j),H.scrolledOffAboveSW.push(...f),
H.anchor&&H.anchor.row===$.row&&z===$.row){...}}
else if(H.scrolledOffBelow.unshift(...j),H.scrolledOffBelowSW.unshift(...f),
H.anchor&&H.anchor.row===A.row&&Y===A.row){...}
Error Messages/Logs
## Stack trace
Captured minified stack from the agent pane:
- createInstance (/$bunfs/root/src/entrypoints/cli.js:502:249)
- PL (/$bunfs/root/src/entrypoints/cli.js:484:58456)
- LYH (/$bunfs/root/src/entrypoints/cli.js:484:88642)
- rZH (/$bunfs/root/src/entrypoints/cli.js:484:87842)
- RD6 (/$bunfs/root/src/entrypoints/cli.js:484:86738)
- iZH (/$bunfs/root/src/entrypoints/cli.js:484:86558)
- jM_ (/$bunfs/root/src/entrypoints/cli.js:484:83272)
- aH (/$bunfs/root/src/entrypoints/cli.js:484:6552)
- LH (/$bunfs/root/src/entrypoints/cli.js:484:5006)
- FH (/$bunfs/root/src/entrypoints/cli.js:484:5318)
All frames land on a single bundled line (`cli.js:484`) at different column offsets — consistent with the Ink component tree throwing deep inside a minified render chain. This is the same stack family as #51818 (v2.1.117, different column offsets because bundle moved in 2.1.119).
## Second trigger — same renderer, different input
The identical `scrolledOffAbove/Below`, `anchor`, `anchorSpan`, `ig_(H,_,q,K,O)` source fragment also leaked into the terminal during a different Bash call of the shape:
cd <another_repo_root> \
&& cat <build_config_file_a> 2>/dev/null | head -60 \
|| cat <build_config_file_b> 2>/dev/null | head -60
Observed conditions in that case:
- Long output → TUI collapsed it as `… +56 lines (ctrl+o to expand)`
- `cd` across shell-snapshot boundary → TUI rendered a `Shell cwd was reset to <original_cwd>` notice
- Both blocks rendered in the same tool-result → renderer state became inconsistent → same `ig_` source dumped
This is strong evidence that the bug sits inside the snippet/scrollback renderer `ig_()` itself, not in either specific input formatter.
## Hypothesis (for triage)
Reading the leaked source of `ig_(H, _, q, K, O)`:
let T = Zq_(H); // viewport clip
if (!T || q > K) return;
let {start: $, end: A} = T;
let z = Math.max(q, $.row); // intersection start
let Y = Math.min(K, A.row); // intersection end
if (z > Y) return; // empty intersection guard
When `grep -n` returns non-contiguous matches, the caller appears to pass a `[q, K]` range spanning the full match span (e.g. row 125 → row 137) while the actual rendered rows are a discrete set (`{125, 127, 137}`). The intersection guard `z > Y` does not catch this case because `z ≤ Y` at the span level, so the loop runs for rows that have no corresponding content, producing either `vw9(_, A, z, Y)` calls with invalid column bounds or `Br6($, ...)` writes against a destination that is not in a renderable state. The thrown error then propagates up through the Ink reconciler and `createInstance` fails.
I can't prove this without sourcemaps, but the two independent triggers both landing on the same minified region of `ig_` strongly suggests this single function is where the fix belongs.
##
Steps to Reproduce
Trigger (primary, precisely isolated)
A Bash tool call of the form:
cd <repo_root> \
&& grep -n "<method_name>" <path/to/source_file.java> 2>/dev/null
where:
- The pattern matches 3 or more non-contiguous line numbers in the same file (e.g. the method is declared, referenced in a
.map(...)call, and overloaded — matches land on lines like 125, 127, 137). - The file contains unrelated code between the matches (any normal Java / Kotlin / TypeScript source).
- The TUI tries to render the result as a snippet block with ellipsis gaps between matches.
Claude Model
Opus
Is this a regression?
I don't know
Last Working Version
_No response_
Claude Code Version
v2.1.119 & v.2.1.118
Platform
Anthropic API
Operating System
macOS
Terminal/Shell
Terminal.app (macOS)
Additional Information
_No response_
This issue has 3 comments on GitHub. Read the full discussion on GitHub ↗