[BUG] Binary tool_result output written as raw bytes into JSONL session files, causing null byte / UTF-8 encoding errors in downstream consumers

Resolved 💬 4 comments Opened Mar 30, 2026 by S2thend Closed May 18, 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 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:

```json
{
"type": "user",
"message": {
"role": "user",
"content": [
{
"type": "tool_result",
"tool_use_id": "...",
"content": "����\^@\^@\^@\^B\^A\^@\^@\^G..."
}
]
}
}

The \^@ 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

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

  1. 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
  1. After the session, open the JSONL file:

~/.claude/projects//.jsonl

  1. Find the tool_result entry corresponding to the binary output.
  2. 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.

View original on GitHub ↗

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