Session invisible in --continue/--resume due to 16KB buffer overflow in qj1

Resolved 💬 2 comments Opened Feb 16, 2026 by chiefexecutive-essential Closed Feb 16, 2026

Bug Description

Sessions with large initial prompts (>16KB) become permanently invisible in claude --continue and --resume pickers, even though the session file is intact and the sessions-index.json has correct metadata.

Environment

  • Claude Code version: 2.1.42
  • OS: Ubuntu 24.04.4 LTS (Linux 6.17.0-14-generic)
  • Platform: linux x86_64

Steps to Reproduce

  1. Start a session in a project directory
  2. Send a large initial prompt (>16KB) — e.g., via EnterPlanMode which passes a full implementation plan
  3. Rename the session with /rename (e.g., "My Important Session")
  4. Continue working until the JSONL file grows significantly (>1MB)
  5. Exit with /exit
  6. Run claude --continue — the session does not appear in the list
  7. Run claude --resume <session-id> — session not found

Root Cause Analysis

The function qj1 reads session JSONL files using a hardcoded 16KB buffer (eS$ = 16384):

// Reads FIRST 16KB → extracts firstPrompt
let D = await I.read(A, 0, eS$, 0);
let U = zj1(B); // firstPrompt from first 16KB

// Reads LAST 16KB → extracts customTitle
let X = Math.max(0, fileSize - eS$);
let J = (X === 0) ? B : await I.read(A, 0, eS$, X);
let F = xYH(J, "customTitle"); // customTitle from last 16KB

Then Tj1 filters sessions:

if (!L.firstPrompt && !L.customTitle) return null; // Session discarded

Problem 1 — firstPrompt not found: When the first user message exceeds 16KB, the buffer can only read the preceding file-history-snapshot (236B) and progress (624B) entries. The actual user message at byte 860 needs ~20KB and doesn't fit.

Example JSONL structure from affected session:

| Line | Type | Size | Cumulative |
|------|------|------|------------|
| 0 | file-history-snapshot | 236 B | 236 B |
| 1 | progress | 624 B | 860 B |
| 2 | user (first prompt) | 20,078 B | 20,938 B |

Buffer ends at 16,384 bytes — line 2 doesn't fit.

Problem 2 — customTitle not found: The custom_title entry (written by /rename) lands mid-file. In a 13.8MB session file, the last 16KB starts at byte 13,853,542 — the title at byte 374,093 is 13.4MB outside the buffer.

Critical design issue: Tj1 overwrites sessions-index.json metadata with values re-parsed from the JSONL:

let L = {...H, isLite: false, firstPrompt: A.firstPrompt, customTitle: A.customTitle, ...};

The sessions-index.json already had the correct customTitle and firstPrompt, but they get replaced with null from the failed buffer reads.

Workaround

Manually appending a custom-title JSON entry to the end of the .jsonl file places it within the last-16KB buffer:

echo '{"type":"custom-title","customTitle":"Session Name","sessionId":"<uuid>"}' >> ~/.claude/projects/<project>/<session-id>.jsonl

Suggested Fixes

| Priority | Fix |
|----------|-----|
| P1 | Don't overwrite sessions-index.json values with nulls from re-parse — trust the index when buffer reads fail |
| P2 | Increase eS$ from 16KB to at least 64KB |
| P3 | When writing custom_title via /rename, always append to end of JSONL (not just mid-stream) |
| P4 | Use sessions-index.json as authoritative source for the session picker, skip JSONL re-parsing when index data is available |

Affected Session Details

  • Session file: 13.8 MB, 1,145 lines JSONL, 460 messages
  • Trigger: Large prompt from EnterPlanMode (implementation plan ~20KB)
  • Duration: ~95 minutes of active work, all lost from picker visibility

Impact

Any session started with a prompt exceeding 16KB that later grows beyond 32KB total will become invisible in --continue/--resume. This can happen naturally when using plan mode, pasting large code blocks, or receiving large context injections.

View original on GitHub ↗

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