Skip to content

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

Closed as not planned

Description

@S2thend

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

  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
  2. After the session, open the JSONL file:
    ~/.claude/projects//.jsonl
  3. Find the tool_result entry corresponding to the binary output.
  4. 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

  1. yurukusa commented on Mar 30, 2026

    @yurukusa

    This is a real problem for anyone building JSONL processing pipelines. As a workaround, you can sanitize the session files post-hoc:

    python3 -c "
    import sys, json
    for line in sys.stdin:
        line = line.replace('\x00', '')  # strip null bytes
        try:
            obj = json.loads(line)
            print(json.dumps(obj, ensure_ascii=False))
        except json.JSONDecodeError:
            pass
    " < "$1"

    Or to prevent binary output from entering the session in the first place, add a PostToolUse hook:

    INPUT=$(cat)
    OUTPUT=$(echo "$INPUT" | jq -r '.tool_output // empty' 2>/dev/null)
    if echo "$OUTPUT" | grep -qP '\x00'; then
      echo '⚠️ Binary output detected in tool result — this may corrupt session JSONL' >&2
    fi
    exit 0
  2. junaidtitan commented on Apr 6, 2026

    @junaidtitan

    Binary tool_result corrupting JSONL is caught by Cozempic v1.6.11's doctor checks — claude-json-corruption and corrupted-tool-use detect and quarantine malformed entries. tool-output-trim also prunes oversized tool results that often contain binary data.

    cozempic doctor --fix

  3. github-actions commented on May 18, 2026

    @github-actions

    Closing for now — inactive for too long. Please open a new issue if this is still relevant.

  4. github-actions commented on Jul 8, 2026

    @github-actions

    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.

  5. locked as resolved and limited conversation to collaborators on Jul 8, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    area:toolsbugSomething isn't workinghas reproHas detailed reproduction stepsplatform:macosIssue specifically occurs on macOSstaleIssue is inactive

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions