[BUG] A dev container sharing ~/.claude deletes the session records of every live host session (PID-namespace mismatch; not fixed by #74566)

Status Fixed / completed
Reported on v2.1.226
Maintainer reply None cached
Activity 2 comments · opened Aug 9, 2026 · closed Aug 25, 2026

Preflight Checklist

  • [x] I have searched existing issues and this hasn't been reported yet
  • [x] This is a single bug report
  • [x] I am using the latest version of Claude Code (2.1.226)

What's Wrong?

Claude Code keeps a record of each running session at $CLAUDE_CONFIG_DIR/sessions/<pid>.json. At startup it sweeps those records and deletes any whose PID isn't alive.

When a dev container shares the host's ~/.claude — the arrangement the dev container docs steer people toward for persisting auth and settings, and which many existing setups use as a bind mount — the container's PIDs live in a different namespace. Every host session's PID genuinely does not exist inside the container, so the sweep reads them all as crashed and deletes the record of every live host session.

Records are written once at startup and never recreated, so nothing recovers on its own. From then on those sessions can't be listed, messaged, or forked, and the only way back is restarting each one. Nothing reports that it happened, and the sessions themselves keep working normally — so the visible symptom is simply that cross-session messaging appears broken, with no clue why.

This is adjacent to #74566 but has a different root cause, and the fix proposed there does not cover it. #74566 is EPERM from a sandbox denying process.kill(pid, 0) being misread as "dead", and its fix is "only treat ESRCH as dead". In the container case the PID is genuinely absent, so the check returns ESRCH legitimately and the record is still deleted. The real mismatch is that PIDs are only meaningful within a namespace, while the registry is keyed by bare PID and shared across the mount.

The reverse direction is worse than a no-op: a container PID such as 230 frequently coincides with a live but unrelated host process, so the host keeps the record and it now points at the wrong process entirely.

What Should Happen?

A session record should only be pruned by a sweeper that can meaningfully evaluate its PID. Options, roughly in order of preference:

  • Stamp each record with a namespace or boot identity — the record already carries procStart — and skip records whose identity doesn't match the sweeper's own.
  • Skip pruning whenever the record's liveness can't be established with confidence, the same conservative stance #74566 asks for.
  • Failing either, detect a config directory shared across PID namespaces and disable the sweep there.

At minimum, deleting a live session's record shouldn't be silent.

Error Messages/Logs

From the container's own debug log, referring to a host session that is still running:

[DEBUG] Prior session exited uncleanly: <sessionId> (v2.1.226)

Steps to Reproduce

Self-contained; uses a throwaway CLAUDE_CONFIG_DIR and never touches your real ~/.claude:

#!/bin/sh
set -eu
T="$(mktemp -d)/claude-config"
mkdir -p "$T/sessions"

# stand in for a live host session
sleep 600 & LIVE=$!
cat > "$T/sessions/$LIVE.json" <<EOF
{"pid":$LIVE,"sessionId":"fake-live-host","cwd":"/tmp","startedAt":1786000000000,"version":"2.1.226","kind":"interactive"}
EOF

ls "$T/sessions"     # -> <LIVE>.json

# any container image with Claude Code installed, sharing that config dir
docker run --rm \
  -v "$T:/home/node/.claude" \
  -e CLAUDE_CONFIG_DIR=/home/node/.claude \
  <image-with-claude-code> claude -p 'ok' >/dev/null 2>&1 || true

ls "$T/sessions"     # -> empty; the live host session's record is gone
kill $LIVE

Expected: the record survives, because the process is alive. Actual: it's deleted, and that host session is silently unlistable and unmessageable from then on.

Real-world trigger: a devcontainer.json containing "source=${localEnv:HOME}/.claude,target=/home/vscode/.claude,type=bind" with CLAUDE_CONFIG_DIR set to that path. Every container start silently de-registers every host session.

Claude Model

Opus 5 (not model-dependent)

Is this a regression?

Not known to have worked previously — the registry has been PID-keyed since cross-session messaging shipped in 2.1.224.

Environment

  • Claude Code 2.1.226
  • macOS 15 (Darwin 23.6.0, arm64), Docker Desktop
  • Containers Debian/Ubuntu-based, Linux PID namespace, VS Code dev containers

View original on GitHub ↗

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