[BUG] Crash on conversation resume: "null is not an object (evaluating 'q.split')" in diff renderer

Status Fixed / completed
Reported on v2.1.81
Maintainer reply None cached
Activity 5 comments · opened Mar 25, 2026 · closed Apr 10, 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?

Resuming a conversation with claude --resume crashes immediately with null is not an object (evaluating 'q.split'). The crash is in the structured patch renderer (pl7) which calls originalFile.split('\n') without a null guard. When originalFile is null (e.g. for a newly created file or one that no longer exists on disk), .split() throws a TypeError and the CLI exits.

What Should Happen?

The conversation should resume and render previous tool results gracefully, even when the original file content is unavailable. A null-safe access (q?.split(...)) or guard should prevent the crash.

Error Messages/Logs

ERROR  null is not an object (evaluating 'q.split')

 pl7 (/$bunfs/root/src/entrypoints/cli.js:3163:2024)
 cX7 (cli.js:2603:45367)
 h9 → a1 → D7_ → nV_ → BQT → iV_ → X7_ → a_ (rendering pipeline)

Steps to Reproduce

Steps to Reproduce:

1. Start a Claude Code conversation that involves file edits (Write or Edit tool) 2. End the conversation 3. Run claude --resume to resume it 4. CLI crashes with the above error before rendering the conversation

Claude Model

Opus

Is this a regression?

Yes, this worked in a previous version

Last Working Version

2.1.81

Claude Code Version

2.1.83

Platform

AWS Bedrock

Operating System

macOS

Terminal/Shell

Other

Additional Information

My terminal is Ghosty with fish shell

View original on GitHub ↗

5 Comments

github-actions[bot] · 5 months ago

Found 1 possible duplicate issue:

  1. https://github.com/anthropics/claude-code/issues/37454

This issue will be automatically closed as a duplicate in 3 days.

  • If your issue is a duplicate, please close it and 👍 the existing issue instead
  • To prevent auto-closure, add a comment or 👎 this comment

🤖 Generated with Claude Code

GeiserX · 5 months ago

Additional root cause analysis

I hit the same crash on v2.1.83 (macOS arm64, Bedrock) resuming a 26,668-line conversation originally created on v2.1.71.

Root cause

The pl7 function (Edit tool success renderer in cli.js:3163) calls originalFile.split('\n') without a null guard. The originalFile value is resolved from file-history-snapshot entries in the conversation JSONL, keyed by the assistant message's UUID. When no snapshot exists for a given UUID, originalFile is null.

In my case, 297 out of 328 Edit tool_use entries had no corresponding file-history-snapshot. The conversation was forked from another session (has a forkedFrom field in line 0) — the fork likely didn't carry over snapshots from the parent.

Minimal fix

// In pl7:
firstLine: (originalFile ?? "").split('\n')[0] ?? null,
fileContent: originalFile ?? "",

Workaround (patching the JSONL)

I was able to resume by injecting missing file-history-snapshot entries into the JSONL. For each assistant message UUID that contained an Edit tool_use but had no snapshot, I added:

{"type":"file-history-snapshot","messageId":"<uuid>","snapshot":{"<file_path>":"<current_file_content>"},"isSnapshotUpdate":false}

This prevents the null crash. Historical diffs won't render accurately (uses current file content instead of the original), but the conversation loads and is fully usable.

Script to automate: read all lines, find Edit tool_use UUIDs missing from snapshot messageIds, inject entries with current disk content, write back. Backup first.

GeiserX · 5 months ago

Working workaround: binary patch (macOS arm64, v2.1.83)

The file-history-snapshot JSONL patching I described above does not work — the renderer resolves originalFile through a different mechanism than snapshot messageId lookup.

What does work is patching the binary directly. The crash is in pl7 where q.split() is called on null originalFile. The fix replaces q.split(...)??null with (q??"").split(...) — exact same byte length, safe in-place patch:

import shutil

binary_path = '/opt/homebrew/Caskroom/claude-code/2.1.83/claude'
backup_path = binary_path + '.bak'
shutil.copy2(binary_path, backup_path)

with open(binary_path, 'rb') as f:
    data = f.read()

original    = b'firstLine:q.split(`\n`)[0]??null,fileContent:q'
replacement = b'firstLine:(q??"").split(`\n`)[0],fileContent:q'

assert len(original) == len(replacement) == 45  # same byte length

patched = data.replace(original, replacement)
# Should replace 2 occurrences (positions ~78M and ~183M in the binary)

with open(binary_path, 'wb') as f:
    f.write(patched)

Then re-sign for macOS:

codesign --remove-signature /opt/homebrew/Caskroom/claude-code/2.1.83/claude
codesign -s - /opt/homebrew/Caskroom/claude-code/2.1.83/claude
xattr -cr /opt/homebrew/Caskroom/claude-code/2.1.83/claude

macOS will show a Gatekeeper warning on first run — go to System Settings → Privacy & Security → Allow Anyway.

Confirmed working: resumes a 26,668-line conversation with 44 subagents and 328 Edit tool calls that previously crashed instantly.

Note: brew upgrade claude-code will overwrite this patch. Re-apply after updates until an official fix ships.
GeiserX · 5 months ago

Update: v2.1.84 has a SECOND crash in the same function

After upgrading to v2.1.84, the originalFile.split() crash is still present (not fixed upstream). Additionally, there's a second null-safety issue: filePath can also be undefined, causing undefined.startsWith().

The actual function in the binary (v2.1.84) is called fs6, not pl7 (source-mapped name):

// Actual binary (v2.1.84), deobfuscated:
function fs6({filePath:H, structuredPatch:_, originalFile:T}, q, {style:A, verbose:$}) {
    let R = H.startsWith(sK());  // CRASH 1: H can be undefined
    return VO.createElement(Kg_, {
        filePath: H,
        structuredPatch: _,
        firstLine: T.split('\n')[0] ?? null,  // CRASH 2: T can be null
        fileContent: T,
        style: A,
        verbose: $,
        previewHint: R ? "/plan to preview" : void 0
    });
}

Updated binary patch for v2.1.84

Two same-length replacements (both found at 2 positions each):

import shutil

binary_path = '/opt/homebrew/Caskroom/claude-code/2.1.84/claude'
shutil.copy2(binary_path, binary_path + '.bak')

with open(binary_path, 'rb') as f:
    data = f.read()

# Fix 1: filePath (H) can be undefined
# R=false means plan preview hint won't show (harmless cosmetic)
data = data.replace(
    b'let R=H.startsWith(sK());',
    b'let R=!1;                '   # 25 bytes, padded with spaces
)

# Fix 2: originalFile (T) can be null (same as v2.1.83 issue)
data = data.replace(
    b'firstLine:T.split(`\n`)[0]??null,fileContent:T',
    b'firstLine:(T??"").split(`\n`)[0],fileContent:T'   # 45 bytes
)

with open(binary_path, 'wb') as f:
    f.write(data)

Then re-sign:

codesign --remove-signature /opt/homebrew/Caskroom/claude-code/2.1.84/claude
codesign -s - /opt/homebrew/Caskroom/claude-code/2.1.84/claude
xattr -cr /opt/homebrew/Caskroom/claude-code/2.1.84/claude

Allow in System Settings → Privacy & Security on first run.

Confirmed working on a 26K-line conversation with 44 subagents.

github-actions[bot] · 4 months ago

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.