"It worked fine yesterday, but claude --resume won't restore anything this morning." If you live inside Claude Code on a real codebase, this scenario is more common than you might think. Losing a conversation mid-task forces you to rebuild context from scratch, and that single hiccup can swallow half an hour before you notice.
I run Claude Code daily across four properties (Claude Lab, Rork Lab, Gemini Lab, Antigravity Lab), and I've stumbled into "the resume list won't show my session" enough times to recognize a pattern. The good news is that the root cause usually falls into one of four buckets, and each bucket has a different place to inspect. The following walkthrough will get you to the actual problem in about five to ten minutes if you go through it in order.
Four reasons claude --resume fails to restore
Claude Code's session machinery is essentially a pair: JSONL transcript files on disk, plus a config directory at ~/.claude/. When restore breaks, the cause typically lives in one of these four places:
- The transcript file isn't where Claude Code is looking — you launched from a different directory, ran
/clearand got a new session ID, or forgot to mount the external drive that holds your work. - A config file is malformed or out of sync —
~/.claude/settings.jsongot corrupted, a hand-edited hook ended up with an empty array, or an editor saved a BOM into the file. - Version drift broke the JSONL schema — you ran
npm i -g @anthropic-ai/claude-codeand the new binary refuses to fully replay older transcripts that mix old and new event shapes. - Path differences across machines — you tried to share
~/.claude/projects/between your home Mac and a work Windows box, or between macOS and WSL, and the path-derived project hash no longer matches.
Below I'll walk through each one with the exact commands I run.
Step 1: Confirm the transcript file is actually on disk
Before assuming anything fancy, just check whether the JSONL transcript still exists. Claude Code writes transcripts to ~/.claude/projects/{hashed-path}/{session-id}.jsonl.
# List the 10 most recently modified transcript files
# (Works on macOS, Linux, and WSL out of the box)
ls -lat ~/.claude/projects/*/*.jsonl 2>/dev/null | head -10
# Expected output (yours will differ):
# -rw-r--r-- 1 user group 12345 Apr 27 08:45 ~/.claude/projects/-Users-user-myrepo/01HA...jsonlIf the directory is empty or doesn't contain the project you were working on, the most likely cause is that you launched claude from a different working directory. The project hash is derived from pwd, so opening a terminal from your dock instead of from inside the repo will produce a different bucket. Try cd into the actual repo path you used yesterday and rerun claude --resume.
While you're here, peek at the last line of the most recent transcript to confirm it isn't truncated mid-write:
# Grab the last line of the newest transcript and pull out its timestamp
LATEST=$(ls -t ~/.claude/projects/*/*.jsonl 2>/dev/null | head -1)
tail -1 "$LATEST" | python3 -c "import sys,json; d=json.loads(sys.stdin.read()); print(d.get('timestamp', d.get('created_at')))"If that prints a clean ISO timestamp, the file is healthy and you should move on to step 2.
Step 2: Audit settings.json and your real working directory
If transcripts exist on disk but claude --resume doesn't list them, it's almost always a config issue. Two failure modes account for the bulk of what I've seen.
The first is ~/.claude/settings.json being malformed. A hand-edited hook with a trailing comma, an editor that silently inserted a UTF-8 BOM, or a half-saved file is enough to make Claude Code fall back to defaults without printing a loud error. Validate it in one line:
# Fast JSON syntax check — silent if valid
python3 -m json.tool ~/.claude/settings.json > /dev/null && echo "OK"If you don't see OK, open the file and look for stray commas or a BOM at the very start. When in doubt, rename it temporarily (mv ~/.claude/settings.json ~/.claude/settings.json.bak) and try --resume again with a clean default config. If it works, your settings are the culprit.
The second mode is path resolution drift via symlinks. On macOS in particular, /Users/me/repo and /private/Users/me/repo resolve to the same place but produce different project hashes:
# Print the canonical (resolved) path of your current directory
pwd -P
# Expected output: /Users/me/repo (or the underlying physical path if a symlink is involved)If pwd and pwd -P disagree, cd to the pwd -P value before launching claude --resume. I recover roughly one in three "missing session" cases this way. For a deeper look at how Claude Code maps configuration to working directories, see my practical guide to CLAUDE.md and the memory system.
Step 3: Suspect a version-drift schema mismatch
"It worked last week, then I ran npm i -g @anthropic-ai/claude-code and --resume stopped working" is almost always JSONL schema drift. From Claude Code 2.x onward, the way tool calls are serialized has been extended several times, and a transcript that mixes events from before and after an upgrade can choke the new binary partway through replay.
# Confirm your installed version
claude --version
# Example: 2.4.1
# Compare the schema version of the first vs. last line of the most recent transcript
LATEST=$(ls -t ~/.claude/projects/*/*.jsonl 2>/dev/null | head -1)
head -1 "$LATEST" | python3 -c "import sys,json; print(json.loads(sys.stdin.read()).get('version','?'))"
tail -1 "$LATEST" | python3 -c "import sys,json; print(json.loads(sys.stdin.read()).get('version','?'))"If the two versions don't match, you have a mixed-schema file. It will usually appear in the --resume list, but replay can stall on a tool call that the new binary expects to deserialize differently. Three options that usually move you forward:
- Trim the file to the recent tail you actually care about:
tail -200 file.jsonl > file.jsonl.new && mv file.jsonl.new file.jsonl— back it up first. - Temporarily reinstall the prior version (
npm i -g @anthropic-ai/claude-code@2.3.x) just long enough to extract what you need, then jump back to current. - Skip
--resumeentirely and bootstrap a new session withclaude --print "summarize what we were working on"plus a quick paste of your goal.
For a full operational view of session lifecycle and why this happens, my Claude Code session management and --resume deep dive walks through the design choices behind the transcript format.
Step 4: Cross-machine and WSL pitfalls
The last bucket — and the one that catches people who try to be clever with cloud storage — is moving sessions across machines. If you store ~/.claude/projects/ in Dropbox or iCloud Drive, remember that the per-project directory name is hashed from the absolute working directory.
A session created at /Users/alice/repo will not match C:\Users\alice\repo on Windows, and it will not match /mnt/c/Users/alice/repo from inside WSL either. Three workarounds that I've found practical:
- Version-control your CLAUDE.md and project notes. Don't try to ship the transcript itself. If the structured context lives in the repo, you can pick up on any machine within seconds.
- Export the conversation as plain text.
cat ~/.claude/projects/.../latest.jsonl | jq -r '.message.content[0].text // empty' | tail -50is enough to capture the last few exchanges, which you can paste into a fresh session elsewhere. - Match the directory layout if you absolutely must. A symlink that exposes
/Users/alice/repoinside WSL is awkward but works for the rare case where you really need the same hash on both sides.
If the recovery still goes sideways, my Claude Code task interruption recovery guide covers how to rebuild from zero without losing momentum.
Safety nets when nothing else works
The four buckets above cover most of what you'll hit, but it's worth keeping a couple of "even if everything fails" moves in your back pocket.
# 1. From all transcripts in the current project, pull the last 10 user messages
# (useful raw material to ask Claude to summarize where you left off)
ls -t ~/.claude/projects/$(echo $PWD | sed 's|/|-|g')/*.jsonl 2>/dev/null | head -1 | \
xargs -I {} sh -c 'jq -r "select(.message.role == \"user\") | .message.content" {}' | tail -10
# 2. Snapshot ~/.claude/projects/ before doing anything destructive
cp -r ~/.claude/projects ~/.claude/projects.bak.$(date +%Y%m%d) && \
echo "✅ Backup saved. Now safe to start fresh."As long as the raw JSONL is preserved, you can always reconstruct the gist later. Which is the bigger lesson here: the best protection against losing a session is regular backups plus offloading durable context into CLAUDE.md so the conversation isn't the only place your project lives.
One thing I want to flag from my own bad habits — most --resume damage I've done to myself was caused by panicking and editing config files aggressively the moment a session looked lost. Walk the four checks above first. And honestly, if those don't get you back, starting a new session with a CLAUDE.md and a three-line summary often returns you to productive work faster than wrestling with a broken transcript.
The whole troubleshooting arc reduces to four questions: Is the transcript on disk? Are the configs valid? Are versions aligned? Are paths consistent across environments? Keep those four in mind and the next time --resume lets you down, you'll have a fix in minutes rather than a lost afternoon.