mv-ing the project dir mid-session permanently breaks --resume (no cwd satisfies both the bucket lookup and the cwd-match check)

Status Open
Reported on v2.1.220
Maintainer reply None cached
Activity 1 comment · opened Jul 27, 2026

Summary

If a Bash tool call inside a session moves the project's own working directory (e.g. mv ~/foo/bar ~/baz/bar where bar is the cwd Claude Code was launched from), and the old location is replaced with a symlink to the new one, --resume becomes permanently broken for that session — from either the old (symlink) path or the new (real) path.

Root cause (from inspecting the transcript JSONL directly)

  • Project sessions are stored in a directory keyed off the cwd at session start (slugified), e.g. ~/.claude/projects/-Users-me-foo-bar/<sessionId>.jsonl.
  • Each line in the transcript also records a "cwd" field, presumably from process.cwd()/the shell's cwd at that point.
  • When the directory itself is renamed/moved while a shell has it open as cwd (not just cd-ing elsewhere), a subsequent Bash call's cwd resolves via the moved inode to the new real path, not the original path string. From that point on, every transcript line records the new path in "cwd", while the session file is still stored under the project bucket keyed to the original path.
  • After that, the transcript itself contains two different cwd values across its lifetime: entries before the move show the old path, entries after show the new path.

This leaves no cwd from which --resume <id> (or the interactive picker) can successfully resume:

  1. cd to the old/symlink path, run claude --resume <id>: the interactive picker finds the session (it's scanning the bucket keyed to this path), but selecting it fails with "This conversation is from a different directory." and suggests re-running the exact same command — a loop. This is presumably because some other check compares current cwd against the last recorded cwd in the transcript, which by now is the new path, not the one you're standing in.
  2. cd to the new/real path, run claude --resume <id>: fails immediately with "No conversation found with session ID: <id>". Presumably because the project bucket is computed by slugifying the current cwd, which now resolves to a different (empty) bucket than the one the session file actually lives in.

So neither candidate cwd satisfies both (a) "which project bucket to search" and (b) "does cwd match the transcript's last recorded cwd" — because those two checks are apparently keyed off different path variants (session-start-cwd vs. last-message-cwd) that diverged the moment the directory was moved mid-session.

Repro

  1. Start claude in ~/work/proj.
  2. Mid-session, ask it to run something equivalent to mv ~/work/proj ~/elsewhere/proj && ln -s ~/elsewhere/proj ~/work/proj (or otherwise move the cwd itself while it's the active shell cwd).
  3. Continue chatting for a bit (so transcript lines after the move exist).
  4. End the session.
  5. Try cd ~/work/proj && claude --resume <id> → interactive picker finds it, but resuming fails with "This conversation is from a different directory," suggesting the identical failing command.
  6. Try cd ~/elsewhere/proj && claude --resume <id>No conversation found with session ID: <id>.

Expected behavior

Either:

  • The project-bucket lookup and the "same directory" check should use the same notion of cwd (both session-start cwd, or both consistently resolve symlinks/realpath), so a directory move mid-session doesn't produce two different recorded truths within one transcript; or
  • If a mid-session directory move is detected, --resume should still succeed from at least one of the two valid paths (old or new), rather than failing from both.

Environment

  • claude --version: 2.1.220
  • macOS
  • Transcript file size in my repro case was ~34MB / ~17.5k lines (long session with many subagents/workflows) — flagging in case size is also a contributing factor to why this wasn't caught by existing directory-mismatch handling, though the root cause above (diverging cwd fields) reproduces independent of size.

Notes

I searched existing issues first — the closest matches are about resume being scoped to the originating directory in general (e.g. picker being cwd-scoped, resume only working from the start dir). This report is narrower: it's specifically about a directory that is moved mid-session, which corrupts the transcript's own cwd bookkeeping such that no single directory (old or new) satisfies resume afterward. Happy to close as duplicate if this turns out to be the same underlying issue as one of those.

View original on GitHub ↗

This issue has 1 comment on GitHub. Read the full discussion on GitHub ↗