[BUG] Windows: /resume picker compares paths case-sensitively - hides sessions and refuses to resume from the same directory when only drive-letter case differs

Status Open
Reported on v2.1.251
Maintainer reply None cached
Activity 0 comments · opened Aug 29, 2026

Environment

  • Claude Code 2.1.251 (native installer), Windows 11 Pro (26200), NTFS
  • Happens across shells; the easiest trigger is mixing cmd.exe and PowerShell (see below)

What's wrong

Windows filesystems are case-insensitive, but the /resume picker compares paths with case-sensitive ===. When the path casing recorded in a session differs from the current shell's casing (typically just the drive letter), two things break:

  1. The session is missing from the default claude -r list for its own project; it only appears after pressing Ctrl+A (show all projects). The all-projects list makes the split visible: sessions from the same physical directory are listed under d:\papriqa\private and D:\papriqa\private as if they were different projects.
  2. Selecting the session then refuses with:
This conversation is from a different directory.

To resume, run:
 cd 'd:\papriqa\private' ; claude --resume 88baf6d7-df21-487c-baa0-7528221d002f

(Command copied to clipboard)

…printed while the shell is sitting in that exact directory (D:\papriqa\private — same path, different case), after which claude exits.

claude -c and claude --resume <id> are unaffected (verified); only the picker is.

Why casing diverges routinely

cmd.exe preserves the drive-letter casing you type (cd /d d:\proj → child process.cwd() is d:\proj), while PowerShell canonicalizes to D:\proj. Start sessions from both shells over time and the "cwd" values recorded in ~/.claude/projects/**/*.jsonl diverge in casing. Nothing else on Windows cares about this; only the resume picker does.

Deterministic repro (verified on 2.1.251, driving the real TUI through a pty)

  1. cmd /c "cd /d d:\some\project && claude -p hi" — lowercase drive letter, so the session records "cwd":"d:\\some\\project".
  2. From PowerShell in the same directory (cwd D:\some\project), run claude -r.
  3. Press Ctrl+A, select that session → the "This conversation is from a different directory" screen above, and claude exits.
  4. Rewrite the cwd values in the session's .jsonl to D:\... (everything else identical) and repeat step 2–3: the same selection now resumes normally. Confirmed A/B on the same machine, same binary.

Root cause, from the shipped bundle

The 2.1.251 bundle contains (deminified for readability):

async function itt(session, f, worktreePaths) {
  let cwd = be();                                  // e.g. D:\papriqa\private
  if (!f || !session.projectPath || session.projectPath === cwd) return null;   // case-sensitive
  if (worktreePaths.some(w => session.projectPath === w ||
      session.projectPath.startsWith(w + sep))) return null;                    // case-sensitive
  // ...
  return `cd ${quote(session.projectPath)} ${sep} claude --resume ${id}`;       // the refusal screen
}

session.projectPath comes from the transcript's recorded cwd; worktreePaths comes from git worktree list, which reports canonical casing. When the recorded casing differs from both, every comparison fails and the picker declares the session foreign to its own directory.

The bundle already has the right tool and uses it elsewhere in the same picker: a helper equivalent to

normalize(p, caseInsensitive) { p = p.replaceAll('\\', '/'); return caseInsensitive ? p.toLowerCase() : p; }

is applied (with the flag on for win32) when matching project storage directories. Applying the same case-folding to the three comparisons above fixes this — it's a few lines.

Workarounds (tested)

  • Works: with the session closed, rewrite the recorded casing inside the session file to the canonical one, e.g.:

``powershell
$f = "$HOME\.claude\projects\d--papriqa-private\<session-id>.jsonl"
(Get-Content $f -Raw).Replace('d:\\papriqa\\private', 'D:\\papriqa\\private') | Set-Content $f -NoNewline
``

  • Works: claude --resume <session-id> directly (skips the picker's check).
  • Does NOT work: renaming the ~/.claude/projects/<slug> folder to the canonical casing — the compared path lives inside the transcript, not in the folder name (verified: no effect).

Prior reports — please do not close as duplicate or stale

This has been reported repeatedly and every report was closed without a fix, so no open issue tracks the CLI bug today: #48218 (this exact bug, auto-closed as a duplicate of #23756), #23756 (good root-cause analysis, closed "not planned" by the stale bot, now locked), #24724 and #34041 (same fate). #84354 and #62288 are open but cover only the VS Code extension's variant of the same case-sensitivity. This report adds a deterministic repro against the current version, the exact failing comparisons in the shipped code, and a tested workaround. Closing it as a duplicate of a locked, stale-closed issue would leave the bug untracked again.

View original on GitHub ↗