Crash on session resume: undefined is not an object (evaluating 'H.startsWith') in Edit result renderer

Status Fixed / completed
Reported on v2.1.87
Maintainer reply ✓ Yes — mhegazy
Activity 7 comments · opened Mar 29, 2026 · closed Apr 10, 2026
💡 Likely answer: A maintainer (mhegazy, contributor) responded on this thread — see the highlighted reply below.

Bug Description

When resuming a previously closed conversation session (selecting it from the session list and pressing Enter), Claude Code crashes with:

ERROR  undefined is not an object (evaluating 'H.startsWith')

The session was working normally before being closed. The crash occurs immediately on resume, before any interaction.

Stack Trace

DR7 (/$bunfs/root/src/entrypoints/cli.js:1772:487)
Ce7 (/$bunfs/root/src/entrypoints/cli.js:2929:18047)
_w (/$bunfs/root/src/entrypoints/cli.js:453:20997)
$O (/$bunfs/root/src/entrypoints/cli.js:453:39538)
Ks (/$bunfs/root/src/entrypoints/cli.js:453:50229)
sEH (/$bunfs/root/src/entrypoints/cli.js:453:86903)
M0 (/$bunfs/root/src/entrypoints/cli.js:453:85865)
aEH (/$bunfs/root/src/entrypoints/cli.js:453:85687)
WDH (/$bunfs/root/src/entrypoints/cli.js:453:82433)
FH (/$bunfs/root/src/entrypoints/cli.js:453:6488)

Root Cause Analysis

The crash is in the DR7 function which renders Edit tool structured results:

function DR7({filePath:H, structuredPatch:_, originalFile:q}, $, {style:K, verbose:O}) {
  let T = H.startsWith(PT()); // <-- crashes here, H is undefined
  ...
}

Unlike YR7 (which guards with if(!H) return null) and vV_ (which uses optional chaining H.file_path?.startsWith), DR7 does not null-check filePath before calling .startsWith().

Thorough data analysis of the session file (1633 lines, 152 Edit/Write tool calls, plus subagent files including compact) found zero malformed entries — all file_path values are valid strings, all tool_use/tool_result pairs are matched, no orphaned entries, no structural anomalies. This suggests the issue is in how the renderer reconstructs/receives props during session reload, not in the persisted data.

Suggested Fix

Add a null guard in DR7, consistent with the pattern used in YR7:

function DR7({filePath:H, structuredPatch:_, originalFile:q}, $, {style:K, verbose:O}) {
  if (!H) return null; // Add this guard
  let T = H.startsWith(PT());
  ...
}

Environment

  • Claude Code version: 2.1.87
  • OS: macOS Darwin 25.2.0 (arm64)
  • Runtime: Bun (per /$bunfs/root/ path prefix)

Session Characteristics

The affected session is a large, long-running conversation with:

  • 1633 JSONL entries in main session file (5.4MB)
  • 152 Edit/Write tool_use entries (all with valid file_path strings)
  • 12+ subagent files including a 1.9MB compact subagent
  • Multiple cross-repository Edit operations (editing files in ~8 different repo directories)
  • Context compaction was triggered during the session

Steps to Reproduce

  1. Have a long conversation session with many Edit/Write tool calls across multiple repositories
  2. Close the session normally
  3. Restart Claude Code and select the session to resume
  4. Crash occurs immediately during conversation render

Workaround

No known workaround yet — the session data appears valid but the renderer crashes during reload.

View original on GitHub ↗

7 Comments

github-actions[bot] · 5 months ago

Found 3 possible duplicate issues:

  1. https://github.com/anthropics/claude-code/issues/40160
  2. https://github.com/anthropics/claude-code/issues/39542
  3. https://github.com/anthropics/claude-code/issues/40424

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

tiffsequence · 5 months ago

Update: Root Cause Identified via Binary Search

Through a binary search on the session's 1633 JSONL entries, we identified the exact line that triggers the crash.

Root Cause

The crash occurs when the conversation renderer encounters a successful Edit tool result (non-error) that contains only a plain text content string (e.g., "The file ... has been updated successfully.") without structuredContent.

The DR7 function is called to render the diff view for this successful Edit result, but receives undefined for filePath because the result data doesn't include structured fields (filePath, structuredPatch, originalFile) that the renderer expects.

The failing Edit results look like this:

{
  "tool_use_id": "toolu_bdrk_XXXXXXXXXXXXXXXXXXXX",
  "type": "tool_result",
  "content": "The file /path/to/project/ecosystem/file.md has been updated successfully."
}

The corresponding tool_use looks normal:

{
  "type": "tool_use",
  "id": "toolu_bdrk_XXXXXXXXXXXXXXXXXXXX",
  "name": "Edit",
  "input": {
    "replace_all": false,
    "file_path": "/path/to/project/ecosystem/file.md",
    "old_string": "Check old-reference.md for function reference",
    "new_string": "Check new-reference.md for function reference"
  }
}

Key Observation

Earlier successful Edit results in the same session (e.g., around line 96) with the identical format do NOT crash. The difference is context-dependent:

  • The crashing Edit result (line 1365) was the 5th of 5 parallel Edit calls in a single assistant turn (lines 1356-1360). The first 4 failed with is_error: true ("File has not been read yet"), and only the 5th succeeded.
  • It appears that when all tool results for a multi-tool-use assistant turn are present, the renderer switches to a "full render" mode that attempts to compute and display diffs — and that code path (DR7) lacks a null guard on filePath.
  • When tool results are incomplete (partial set), the renderer uses a "pending" view that doesn't trigger DR7.

How We Found It

  1. Data analysis — Exhaustively searched all JSONL entries, subagent files, and compact files for null/missing file_path/filePath values. Found nothing — all stored data is structurally valid.
  2. Binary search — Truncated the session file at different points:
  • 1362 lines: no crash
  • 1366 lines: crash
  • Narrowed to line 1365 (index) as the exact trigger — the successful Edit result that completes the 5/5 tool result set.
  1. Pattern confirmation — The session contains 93 successful Edit results with the same plain-text format. The crash triggers when any of them completes a full set of tool results for a multi-tool-use turn.

Workaround

We fixed the session file by converting all 93 successful Edit results to error format:

# For each successful Edit result with plain text content:
b['is_error'] = True
b['content'] = f"<tool_use_error>{b['content']}</tool_use_error>"

This prevents the diff renderer (DR7) from being invoked, and the session now loads successfully.

For other users hitting this error: Back up your session file (.jsonl), then run a script to mark successful Edit tool results as errors. The conversation context is preserved and the session becomes resumable. See the follow-up comment for a complete copy-paste script.

Suggested Fix

Add a null guard in DR7, consistent with the pattern used in YR7:

// Current (crashes):
function DR7({filePath:H, structuredPatch:_, originalFile:q}, $, {style:K, verbose:O}) {
  let T = H.startsWith(PT()); // H is undefined → crash
  ...
}

// Fixed:
function DR7({filePath:H, structuredPatch:_, originalFile:q}, $, {style:K, verbose:O}) {
  if (!H) return null; // Guard against undefined filePath
  let T = H.startsWith(PT());
  ...
}

Additionally, the caller (Ce7) should validate that the structured result data contains filePath before dispatching to DR7, particularly for Edit results that only have plain text content (no structuredContent).

tiffsequence · 5 months ago

Not a duplicate — this issue provides the only known workaround

The flagged issues are indeed the same underlying bug:

  • #39542 (v2.1.84, macOS) — same crash, no root cause analysis, no workaround
  • #40160 (v2.1.86, Windows/Bedrock) — same crash, no workaround
  • #40424 (v2.1.86, Linux) — excellent root cause analysis identifying replace_all: true + empty new_string as a trigger, but no workaround beyond manually removing JSONL entries and repairing the parentUuid chain

This issue is the only one that provides a scriptable workaround that preserves the full conversation context and allows the session to resume:

import json

fname = "YOUR_SESSION_ID.jsonl"

# Collect Edit tool_use IDs
edit_ids = set()
for line in open(fname):
    try:
        o = json.loads(line)
        c = o.get('message', {}).get('content', [])
        if isinstance(c, list):
            for b in c:
                if isinstance(b, dict) and b.get('type') == 'tool_use' and b.get('name') == 'Edit':
                    edit_ids.add(b['id'])
    except: pass

# Convert successful Edit results to error format to bypass diff renderer
lines = open(fname).readlines()
output = []
for line in lines:
    try:
        o = json.loads(line)
        c = o.get('message', {}).get('content', [])
        modified = False
        if isinstance(c, list):
            for b in c:
                if (isinstance(b, dict) and b.get('type') == 'tool_result'
                    and b.get('tool_use_id') in edit_ids
                    and not b.get('is_error')
                    and isinstance(b.get('content'), str)
                    and 'has been updated successfully' in b.get('content', '')):
                    b['is_error'] = True
                    b['content'] = f"<tool_use_error>{b['content']}</tool_use_error>"
                    modified = True
        output.append(json.dumps(o) + '\n' if modified else line)
    except:
        output.append(line)

with open(fname, 'w') as f:
    f.writelines(output)

Back up your session file first. Session files are in ~/.claude/projects/<project-hash>/<session-id>.jsonl.

This also adds new findings to the root cause: the crash specifically triggers when a successful Edit result completes a full set of tool results for a multi-tool-use assistant turn, causing the renderer to switch from a partial/pending view to a full diff rendering view — which is where the missing null guard on filePath in DR7 causes the crash.

Keeping this issue open so users searching for the workaround can find it.

Kequans · 5 months ago

same problem, and the fix script works.

LEON-gittech · 5 months ago

Confirmed the workaround script works. Had the same crash on v2.1.85/2.1.87 with a large session (10620 lines, 275 Edit tool calls). The script from the second comment patched 269 successful Edit results and the session now resumes successfully. Thanks @tiffsequence for the thorough root cause analysis and fix!

mhegazy contributor · 4 months ago

Should be fixed in v2.1.99

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.