Case-insensitive collision in project temp-dir path breaks Bash entirely after a case-only rename (macOS/APFS)
Summary
A case-only rename of a project directory (e.g. Foo → foo via macOS's standard
two-step rename) leaves a stale, wrong-case entry under/private/tmp/claude-501/<encoded-cwd>/. Every new session then fails all Bash
calls with:
task output swap refused (tasks dir moved or linked):
/private/tmp/claude-501/<encoded-cwd>/<session-id>/tasks/<file>.output
Same root cause as #54865 (path-encoding nondeterminism in the project-dir slug
function), but a more severe symptom: instead of an empty /resume picker, the
Bash tool stops working entirely for the project, for every new session, until
a human manually finds and deletes the stray directory.
CLI version
2.1.251 (Claude Code), macOS 25.5.0 (Darwin), APFS (case-insensitive,
case-preserving).
Reproduction
- Create a project directory with uppercase letters, e.g.
~/src/Foo. - Start a Claude Code session there. This creates
/private/tmp/claude-501/-Users-<user>-src-Foo/<session-id>/.
- Rename the directory to lowercase via the two-step technique required on a
case-insensitive volume: mv Foo foo-tmp && mv foo-tmp foo.
- Start a new Claude Code session in
~/src/foo. Any Bash tool call fails
with the "task output swap refused... moved or linked" error.
Root cause
/private/tmp is on a case-insensitive-but-case-preserving APFS volume, same
as the macOS reports in #54865. The project-dir slug encodes the cwd path
(case included) into /private/tmp/claude-501/<encoded-cwd>/. Once one
session creates that directory with the old (uppercase) case, later sessions
computing the new (lowercase) encoded name resolve, via the case-insensitive
filesystem, to the same directory — but its on-disk name doesn't literally
match the freshly-computed name. A safety check that verifies the resolved
tasks dir matches the expected path (presumably guarding against symlink
swaps) treats this case mismatch as "moved or linked" and refuses to write,
breaking the tool completely instead of falling back to the existing
directory or recreating it under the correct case.
Evidence
/private/tmp/claude-501/-Users-<user>-...-<PROJECT-UPPER>/ held five session
subdirectories, all from new sessions started after the rename, while~/.claude/projects/-Users-<user>-...-<project-lower>/ — a separate subsystem
that appears to recompute the slug from a freshly-normalized cwd rather than
reuse a cached directory — correctly used the lowercase form. Deleting the
stray uppercase directory under /private/tmp/claude-501/ immediately fixed
new sessions.
Suggested fix
Same suggestions as #54865, applied to this subsystem too:
- Canonicalize (at minimum, case-fold) the cwd before encoding it into any
project-scoped filesystem path.
- If a case-insensitive collision is unavoidable, detect it and fail open
(reuse the existing directory) instead of refusing all Bash calls.
- At minimum, don't leave a session permanently broken — regenerate the
tasks dir under the currently-expected path rather than aborting.
Related
#54865 — closed as stale/not-planned, but macOS case-insensitivity was
independently reproduced in its comments too. This issue shows the same root
cause has a more severe, tool-breaking symptom, not just a resume-picker one.