claude-code - 💡(How to fix) Fix [BUG] Bash output renderer dumps Ink scrollback source when grep -n returns non-contiguous matches (v2.1.119, Agent Teams) [1 participants]

Official PRs (…)
ON THIS PAGE

Recommended Tools

×6

Utilities matched from this issue’s tags and category — try them while you read without losing context.

GitHub issue graph ai analysis

Paste a GitHub issue URL. We fetch that issue, discover linked issues from bodies/comments/timeline, collect linked pull requests, and produce a structured English report.

The report is written in English Markdown for sharing and archival.

Helpful · Quick feedback

Loading…
GitHub stats
anthropics/claude-code#52673Fetched 2026-04-24 10:42:48
View on GitHub
Comments
0
Participants
1
Timeline
5
Reactions
0
Author
Participants
Timeline (top)
labeled ×5

Error Message

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).

Root Cause

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.

Code Example

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){...}

---

## 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.

##

---

cd <repo_root> \
  && grep -n "<method_name>" <path/to/source_file.java> 2>/dev/null
RAW_BUFFERClick to expand / collapse

Preflight Checklist

  • I have searched existing issues and this hasn't been reported yet
  • This is a single bug report (please file separate reports for different bugs)
  • 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:

  1. 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).
  2. The file contains unrelated code between the matches (any normal Java / Kotlin / TypeScript source).
  3. 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

extent analysis

TL;DR

The bug can be fixed by modifying the ig_ function to handle non-contiguous line numbers correctly, specifically by adjusting the intersection guard and loop bounds.

Guidance

  • Review the ig_ function to understand how it handles viewport clipping and intersection calculations.
  • Verify that the z > Y intersection guard is not sufficient for non-contiguous line numbers and adjust the loop bounds accordingly.
  • Test the modified ig_ function with the provided trigger to ensure it renders the snippet block correctly.
  • Consider adding additional logging or debugging statements to help identify the root cause of the issue.

Example

let T = Zq_(H);
if (!T || q > K) return;
let {start: $, end: A} = T;
let z = Math.max(q, $.row);
let Y = Math.min(K, A.row);
// Adjust the intersection guard and loop bounds to handle non-contiguous line numbers
if (z > Y || !hasContentBetweenRows(z, Y)) return;

Notes

The provided hypothesis and stack trace suggest that the issue lies within the ig_ function, but without sourcemaps, it's difficult to pinpoint the exact cause. The fix may require additional modifications to the ig_ function or other related code.

Recommendation

Apply a workaround by modifying the ig_ function to handle non-contiguous line numbers correctly, as the root cause of the issue appears to be within this function.

Vote matrix · Quick signals

Works
Did the solution work? Tap to confirm.
Easy Fix
Was it a quick fix?
Time Saver
Did it save you time?
Blocking
Was it severely blocking?
Common Issue
Are others likely hitting this too?
Flaky / Intermittent
Is it intermittent?
Verified / Reproducible
Can you reproduce it reliably?
Loading…

Still need to ship something?

×6

Another batch ranked right after the header list — different links, same matching logic.

Back to top recommendations

TRENDING

claude-code - 💡(How to fix) Fix [BUG] Bash output renderer dumps Ink scrollback source when grep -n returns non-contiguous matches (v2.1.119, Agent Teams) [1 participants]