Atomic file writes fail with multi-level symlinks (nix home-manager)

Resolved 💬 4 comments Opened Dec 30, 2025 by andrewgazelka Closed Feb 21, 2026

Description

Claude Code only resolves one level of symlinks when performing atomic file writes. When using nix home-manager with mkOutOfStoreSymlink, this creates a multi-level symlink chain through the read-only nix store, causing repeated EACCES errors on startup.

Symlink chain

~/.claude.json
  → /nix/store/...-home-manager-files/.claude.json
    → /nix/store/...-hm_.claude.json
      → /Users/user/.config/nix/claude/global/.claude.json  (writable!)

Current behavior

Claude Code resolves only the first symlink level, sees the target is in /nix/store/, then tries to create a temp file there for atomic write:

Writing through symlink: ~/.claude.json -> /nix/store/...-home-manager-files/.claude.json
Writing to temp file: /nix/store/...-home-manager-files/.claude.json.tmp...
Failed to write file atomically: EACCES: permission denied
Falling back to non-atomic write

This happens multiple times during startup (adds noise to debug logs and likely minor latency).

Expected behavior

Claude Code should use realpath() (equivalent to readlink -f) to fully resolve the symlink chain to the actual writable file before determining the temp file directory.

Environment

  • macOS (Darwin 25.2.0)
  • Claude Code v2.0.76
  • nix with home-manager using mkOutOfStoreSymlink

Reproduction

  1. Use nix home-manager to manage ~/.claude.json with mkOutOfStoreSymlink
  2. Run claude --debug
  3. Observe repeated EACCES errors in debug log for atomic write attempts

View original on GitHub ↗

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