Repository navigation
Description
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?
When Claude Code executes a tool whose output contains binary data (e.g. reading a binary file, running an executable that produces binary output), the raw bytes are written directly into the JSONL session file as a plain
JSON string with no encoding step. This embeds null bytes (\x00) and other control characters that are illegal in strict UTF-8 contexts.
Inspecting the .jsonl file on disk reveals entries like:
{
"type": "user",
"message": {
"role": "user",
"content": [
{
"type": "tool_result",
"tool_use_id": "...",
"content": "����\u0000\u0000\u0000\u0002\u0001\u0000\u0000\u0007..."
}
]
}
}
The \u0000 null bytes and replacement characters (U+FFFD, i.e. EFBFBD) are embedded literally in the JSON string value.
### What Should Happen?
Binary tool output should be detected and safely encoded before being written to the JSONL file. For example:
- Base64-encode the content and store it with a type marker, e.g. {"type": "base64", "data": "..."}, or
- Sanitize non-UTF-8-safe bytes (null bytes, lone surrogates, control characters) before writing the JSON line.
This would make session JSONL files safe for all downstream consumers (databases, search indexes, log shippers, etc.) without data loss.
### Error Messages/Logs
```shell
Error observed when inserting the content into PostgreSQL:
ERROR: invalid byte sequence for encoding "UTF8": 0x00
SQLite accepts it silently (permissive behavior), which masks the issue at the storage layer.Steps to Reproduce
- Ask Claude Code to run a tool that reads or outputs binary data, e.g.:
- cat /usr/bin/ls (or any system binary)
- Any tool invocation where the shell output contains binary bytes - After the session, open the JSONL file:
~/.claude/projects//.jsonl - Find the tool_result entry corresponding to the binary output.
- Inspect the content field — it will contain raw binary bytes embedded as a string, including \x00 null bytes and U+FFFD replacement characters.
Confirmed affected session file (for reference):
- Project: open-source-general-agents / wormhole-eventflow
- Session UUID: de225291-aec8-4626-a0fb-a3dd28191cfe
- Message UUID: fbfce6ea-86c6-4ea5-9e07-912af8a9b414
- First 40 bytes of content (hex): EFBFBD EFBFBD EFBFBD EFBFBD 00 00 00 02 01 00 00 07 00 00 00 03 00 00 40 00...
Claude Model
None
Is this a regression?
No, this never worked
Last Working Version
No response
Claude Code Version
2.1.87
Platform
Anthropic API
Operating System
macOS
Terminal/Shell
Terminal.app (macOS)
Additional Information
This was discovered while building a tool (vibe-history) that syncs Claude Code session history to PostgreSQL. SQLite accepts the null bytes silently, so the bug only surfaces when writing to a strict UTF-8 store.
The workaround currently in place is a fallback sanitization layer on the consumer side that detects PostgreSQL encoding errors and re-encodes the content using JSON escape sequences. However, the correct fix is at the
source — Claude Code should not write non-UTF-8-safe bytes into JSONL in the first place.
The Mach-O binary section names visible in the data (__TEXT, __DATA, __stubs, __cstring, etc.) confirm this is a real compiled binary that ended up as a tool result content string.
Activity
yurukusa commentedon Mar 30, 2026
This is a real problem for anyone building JSONL processing pipelines. As a workaround, you can sanitize the session files post-hoc:
Or to prevent binary output from entering the session in the first place, add a PostToolUse hook:
junaidtitan commentedon Apr 6, 2026
Binary tool_result corrupting JSONL is caught by Cozempic v1.6.11's doctor checks —
claude-json-corruptionandcorrupted-tool-usedetect and quarantine malformed entries.tool-output-trimalso prunes oversized tool results that often contain binary data.cozempic doctor --fixgithub-actions commentedon May 18, 2026
Closing for now — inactive for too long. Please open a new issue if this is still relevant.
github-actions commentedon Jul 8, 2026
This issue has been automatically locked since it was closed and has not had any activity for 7 days. If you're experiencing a similar issue, please file a new issue and reference this one if it's relevant.