[BUG] Lack of tool output fidelity

Status Open
Reported on v2.1.232
Maintainer reply None cached
Activity 1 comment · opened Aug 14, 2026

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?

When a bash command is run in an interactive Claude Code session via the ! prefix, the rendered console output collapses runs of spaces/tabs and drops leading blank output — even though the underlying session transcript (.jsonl) contains the correct, unmangled bytes. This is a display bug in the CLI's terminal renderer, not a data-capture bug: the same bytes that render wrong on screen are stored correctly on disk.

command
{ echo foo;echo;echo bar; }|cat -n
cli render
     1     foo
2
     3     bar

Claude cannot tell you anything about what ACTUALLY renders. It only knows what is available to the tools.

What Should Happen?

The 2nd line shouldn't have the prefix stripped out.

Error Messages/Logs

No errors etc.

Steps to Reproduce

  1. Start interactive session
  2. Go into command mode (!)
  3. Paste command from above
  4. Observe rendered output

Claude Model

Sonnet (default)

Is this a regression?

I don't know

Last Working Version

_No response_

Claude Code Version

2.1.232 (Claude Code)

Platform

Anthropic API

Operating System

macOS

Terminal/Shell

Other

Additional Information

Here was my investigation.

Claude Code CLI: interactive console rendering mangles whitespace in bash output

Summary

When a bash command is run in an interactive Claude Code session via the ! prefix, the
rendered console output collapses runs of spaces/tabs and drops leading blank output —
even though the underlying session transcript (.jsonl) contains the correct, unmangled
bytes. This is a display bug in the CLI's terminal renderer, not a data-capture bug: the
same bytes that render wrong on screen are stored correctly on disk.

Repro

Run the following in an interactive Claude Code session, prefixed with !:

echo "RENDER-MANGLING-$(date +%s)";
d() { echo "--- [${1+${1@Q}}] & [${2+${2@Q}}] ---"; echo "${1-}${2-}"; echo "${1-}foo bar${2-}"; echo "${1-}       ${2-}"; echo "${1-}foo    ${2-}"; echo "${1-}       ${2-}"; echo "${1-}    bar${2-}"; };
d; d $'   1\t'; d $'   x\t';
d; d '' $'   1\t'; d '' $'   x\t';

Note: if ${x@Q} isn't supported by your shell, substitute $(printf '%q' "${x-}").

The first line of output is a timestamped slug used below to locate this run in the raw
transcript.

For our reported case: slug = RENDER-MANGLING-1786737825

Expected

Piping the same command's real stdout through
jq -sR 'split("\n")|map("\(.)\n")[]' (which prints each line with escapes visible, so
trailing spaces/tabs and blank lines are unambiguous) gives:

"RENDER-MANGLING-1786737825\n"
"--- [] & [] ---\n"
"\n"
"foo bar\n"
"       \n"
"foo    \n"
"       \n"
"    bar\n"
"--- [$'   1\\t'] & [] ---\n"
"   1\t\n"
"   1\tfoo bar\n"
"   1\t       \n"
"   1\tfoo    \n"
"   1\t       \n"
"   1\t    bar\n"
"--- [$'   x\\t'] & [] ---\n"
"   x\t\n"
"   x\tfoo bar\n"
"   x\t       \n"
"   x\tfoo    \n"
"   x\t       \n"
"   x\t    bar\n"
"--- [] & [] ---\n"
"\n"
"foo bar\n"
"       \n"
"foo    \n"
"       \n"
"    bar\n"
"--- [''] & [$'   1\\t'] ---\n"
"   1\t\n"
"foo bar   1\t\n"
"          1\t\n"
"foo       1\t\n"
"          1\t\n"
"    bar   1\t\n"
"--- [''] & [$'   x\\t'] ---\n"
"   x\t\n"
"foo bar   x\t\n"
"          x\t\n"
"foo       x\t\n"
"          x\t\n"
"    bar   x\t\n"
"\n"

Actual

The output as it appears in the interactive console was copy-pasted and re-fed through the
same jq filter to make the mangling explicit:

$ cat <<'_EOF_' | jq -sR 'split("\n")|map("\(.)\n")[]'
<pasted from claude-cli render>
_EOF_
"RENDER-MANGLING-1786737825\n"
"--- [] & [] ---\n"
"\n"
"foo bar\n"
"\n"
"foo\n"
"\n"
"    bar\n"
"--- [$'   1\\t'] & [] ---\n"
"1\n"
"   1       foo bar\n"
"1\n"
"   1       foo\n"
"1\n"
"   1           bar\n"
"--- [$'   x\\t'] & [] ---\n"
"   x\n"
"   x       foo bar\n"
"   x\n"
"   x       foo\n"
"   x\n"
"   x           bar\n"
"--- [] & [] ---\n"
"\n"
"foo bar\n"
"\n"
"foo\n"
"\n"
"    bar\n"
"--- [''] & [$'   1\\t'] ---\n"
"1\n"
"foo bar   1\n"
"1\n"
"foo       1\n"
"1\n"
"    bar   1\n"
"--- [''] & [$'   x\\t'] ---\n"
"   x\n"
"foo bar   x\n"
"          x\n"
"foo       x\n"
"          x\n"
"    bar   x\n"
"\n"

Comparing Expected vs. Actual, the rendering issue has (at least) three distinct symptoms:

  1. Tabs are expanded/mangled inconsistently. 1\t alone renders as 1, but

1\tfoo bar renders as 1 foo bar (tab expanded to spaces, leading spaces
preserved only when followed by more text on the same line).

  1. Whitespace-only lines are altered or lost. Lines that are pure spaces (e.g. the

" \n" lines) don't appear at all in the actual output for the [] & [] case.

  1. The mangling is content-dependent, not just position-dependent — compare the

$' 1\t' case (leading whitespace stripped down to 1) against the $' x\t' case
(leading whitespace preserved as x) for otherwise identical line shapes. This rules
out a simple "always trim column N" theory and suggests something like tab-stop
expansion combined with a line-diffing/redraw step that's misidentifying repeated or
short lines.

Verification

To confirm this is a rendering issue rather than data loss in the transcript itself, the
raw session .jsonl file was inspected directly, bypassing the console renderer entirely:

grep -F "<slug>" "$(ls -t ~/.claude/projects/<project-dir>/*.jsonl | head -1)" |
  jq -j 'select(.message.content)|.message.content'|jq -sR 'split("\n")|map("\(.)\n")[]'

Verbatim output of that command:

"<bash-stdout>RENDER-MANGLING-1786737825\n"
"--- [] &amp; [] ---\n"
"\n"
"foo bar\n"
"       \n"
"foo    \n"
"       \n"
"    bar\n"
"--- [$'   1\\t'] &amp; [] ---\n"
"   1\t\n"
"   1\tfoo bar\n"
"   1\t       \n"
"   1\tfoo    \n"
"   1\t       \n"
"   1\t    bar\n"
"--- [$'   x\\t'] &amp; [] ---\n"
"   x\t\n"
"   x\tfoo bar\n"
"   x\t       \n"
"   x\tfoo    \n"
"   x\t       \n"
"   x\t    bar\n"
"--- [] &amp; [] ---\n"
"\n"
"foo bar\n"
"       \n"
"foo    \n"
"       \n"
"    bar\n"
"--- [''] &amp; [$'   1\\t'] ---\n"
"   1\t\n"
"foo bar   1\t\n"
"          1\t\n"
"foo       1\t\n"
"          1\t\n"
"    bar   1\t\n"
"--- [''] &amp; [$'   x\\t'] ---\n"
"   x\t\n"
"foo bar   x\t\n"
"          x\t\n"
"foo       x\t\n"
"          x\t\n"
"    bar   x</bash-stdout><bash-stderr></bash-stderr>\n"

This matches the Expected output byte-for-byte (modulo the &amp; XML-escaping of &
in the transcript), confirming the bug is confined to the terminal renderer — the captured
transcript data is correct.

Environment

  • macOS (Darwin 25.5.0), zsh/bash shell (/opt/homebrew/bin/bash).
  • Claude Code (CLI 2.1.232), output rendered in an interactive chat session.
  • WezTerm (bundle=com.github.wez.wezterm, version=20260619-100849-cd4b4fd2)

View original on GitHub ↗

This issue has 1 comment on GitHub. Read the full discussion on GitHub ↗