[BUG] `/branch` writes every message twice, creating a branch session ~1.5x larger than parent

Resolved 💬 3 comments Opened Mar 28, 2026 by Skydev0h Closed Jun 2, 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?

/branch creates a branch session file that is significantly larger than the parent session. In my case: parent = 8,892 lines (33 MB), branch = 12,056 lines (42 MB).

Investigation shows the branch function writes two copies of every message to the output file — one with a forkedFrom field (the intended forked entry) and one without (an unintended duplicate). This results in 4,205 UUIDs appearing exactly twice in the branch JSONL.

Breakdown of the branch file (12,056 entries):

  • 7,828 entries WITH forkedFrom — the intended forked messages
  • 4,228 entries WITHOUT forkedFrom — unintended duplicates
  • 4,205 UUIDs appear exactly 2 times
  • All 12,056 entries have the branch's sessionId (not the parent's)

What Should Happen?

The branch should contain each message exactly once. The branch file should be approximately the same size as the parent session at the time of branching.

Error Messages/Logs

# No error — /branch succeeds silently but produces an oversized file.

$ wc -l parent-session.jsonl
8892    # parent at time of investigation (was ~8,378 at branch time)

$ wc -l branch-session.jsonl
12056   # branch — 44% more lines than the parent had

# UUID duplication check:
# Total unique UUIDs in branch: 7,836
# UUIDs appearing exactly 2 times: 4,205

Steps to Reproduce

  1. Work in a Claude Code session until it has meaningful conversation history
  2. Run /branch <name>
  3. Compare line counts: wc -l ~/.claude/projects/<project>/*.jsonl
  4. Check for duplicate UUIDs in the branch file:
import json
from collections import Counter
uuids = Counter()
with open('branch-session.jsonl') as f:
    for line in f:
        d = json.loads(line)
        uuid = d.get('uuid')
        if uuid:
            uuids[uuid] += 1
dupes = sum(1 for v in uuids.values() if v > 1)
print(f"UUIDs appearing >1 time: {dupes}")

Claude Model

Opus

Is this a regression?

I don't know

Last Working Version

_No response_

Claude Code Version

2.1.86

Platform

Anthropic API

Operating System

Ubuntu/Debian Linux

Terminal/Shell

Windows Terminal

Additional Information

Root Cause (from deobfuscated source)

The branch function (minified as Yf9 in v2.1.86) builds two arrays in one loop:

let D = null, w = [], M = [];
for (let j of Y) {
    let X = {...j, sessionId: $, parentUuid: D, isSidechain: false,
             forkedFrom: {sessionId: q, messageUuid: j.uuid}};  // WITH forkedFrom
    let J = {...j, sessionId: $};                                 // WITHOUT forkedFrom
    M.push(J);       // pushed to M (returned as serializedMessages)
    w.push(gH(X));   // pushed to w (written to file)
    if (j.type !== "progress") D = j.uuid;
}
// writes w to the branch JSONL file
await TSH.writeFile(_, w.join('\n') + '\n', ...);
// returns M as serializedMessages
return {sessionId: $, ..., serializedMessages: M, ...};

The caller then does $.resume(forkPath, serializedMessages, "fork"), which loads the M array into the runtime. The runtime re-persists the pre-compact portion of these messages back to the same branch JSONL — resulting in those messages appearing twice: once from w (with forkedFrom) and once from the resume replay (without forkedFrom).

Evidence confirms an exact split at the compact boundary:

  • Messages before compact point (line 0–4,204): ALL duplicated (4,205 UUIDs × 2)
  • Messages after compact point (line 4,205+): ALL single (3,631 UUIDs × 1)
  • Every duplicated UUID has exactly one entry with forkedFrom and one without — zero exceptions

Suggested fix

The resume(path, serializedMessages, "fork") call should not re-persist messages that are already written to the branch file by the branch function. Either:

  1. Skip writing serializedMessages to the JSONL during fork-mode resume (they're already in w)
  2. Or deduplicate on write — if a UUID already exists in the file, don't append it again

The root cause was identified by extracting strings from the compiled binary at ~/.local/share/claude/versions/2.1.86 and cross-referencing with the JSONL structure of the branch file. The forkedFrom field presence/absence and the exact split at the compact boundary were the key evidence.

View original on GitHub ↗

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