Background jobs stamped with stale/non-existent originCwd from the open project tab (not terminal cwd), causing opaque "working directory no longer exists" startup failures

Resolved 💬 2 comments Opened Jun 5, 2026 by pai-scaffolde Closed Jun 8, 2026

Summary

Claude Code stamps background (daemon) jobs with the originCwd of the currently-displayed project tab at submission time. It does not read the terminal's process.cwd(), and it does not validate that the path still exists. Once a project whose directory lives under /private/tmp (or any ephemeral/removable path) is registered, every subsequent background job submitted from that tab inherits the same path. When macOS later purges /private/tmp, those jobs fail to start with:

Session can't start — working directory no longer exists: /private/tmp/<dir>

Impact

  • Background jobs become unstartable through no fault of the user. The failure is opaque ("working directory no longer exists") and gives no hint that the cwd was inherited from a stale project tab rather than the terminal's actual working directory.
  • Unrelated, later jobs submitted from the same tab all silently inherit the dead path.
  • The stale project key persists in ~/.claude.json, so re-selecting the old tab re-triggers the failure indefinitely.

Steps to reproduce

  1. Open/launch a Claude Code session whose working directory is under /private/tmp (e.g. a scratch/verify dir). This registers a project key for that path in ~/.claude.json.
  2. From that project tab, submit one or more background jobs. They are stamped with originCwd = /private/tmp/<dir>.
  3. Let macOS purge /private/tmp (reboot, or the ~3-day periodic /tmp cleanup).
  4. The background jobs now fail to start with Session can't start — working directory no longer exists: /private/tmp/<dir>, even for jobs whose intent has nothing to do with that directory.

Root cause (observed)

The cwd written into each job comes from app/UI project state, not the terminal. The binary exposes app-level setCwdState/getCwdState and an originCwd field that are independent of process.cwd(). originCwd is persisted into the job's state.json and used for chdir at startup, with no existence check, and the originating project key is never pruned from ~/.claude.json when its directory disappears.

Expected behavior

When creating/launching a background job, Claude Code should:

  1. Validate that originCwd exists before writing it into the job's state.json / before chdir.
  2. If the path is gone, fall back to $HOME (or the nearest existing ancestor) and surface a clear, recoverable message rather than a hard startup failure.
  3. Optionally, prune project keys in ~/.claude.json whose directories no longer exist.

Environment

  • Claude Code 2.1.162 (~/.local/bin/claude, ~/.local/share/claude/versions/2.1.162), daemon-backed background jobs.
  • macOS (Darwin 25.6.0).

Workaround

Don't launch Claude sessions from /private/tmp (purged on reboot / ~3-day periodic cleanup); use a persistent directory. To recover, with the app quit: remove the stale project key from ~/.claude.json and delete the orphaned ~/.claude/jobs/<id> records. A small status/prune doctor script that scans jobs for a missing originCwd and prunes ~/.claude.json project keys whose directory no longer exists makes this repeatable.

View original on GitHub ↗

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