Skip to content

CLAUDE_CODE_TMPDIR not respected for CWD tracking files on multi-user servers #31024

Description

@ShonaDouglasKT

Description

On shared multi-user Linux servers, Claude Code's CWD tracking files (/tmp/claude-<hex>-cwd) accumulate in /tmp/ and collide across users, causing "Permission denied" errors in stderr. The CLAUDE_CODE_TMPDIR environment variable does not fix this — it is only partially respected.

Steps to reproduce

  1. Set up a shared Linux server with multiple users running Claude Code
  2. Set CLAUDE_CODE_TMPDIR=/var/tmp/claude (or any custom path)
  3. Have multiple users run Claude Code sessions over time
  4. Observe /tmp/claude-*-cwd files accumulating, owned by different users
  5. Eventually a session gets a hex ID that collides with an existing file owned by another user → EACCES

Expected behaviour

CLAUDE_CODE_TMPDIR should control where CWD tracking files are written, and they should be scoped per user (e.g. by UID) to prevent cross-user collisions.

Actual behaviour

CWD tracking files ignore CLAUDE_CODE_TMPDIR and always write to /tmp/claude-<hex>-cwd with no user scoping.

In the minified source (v2.1.68), the CWD file path depends on whether sandbox mode is enabled:

  • Sandbox path (useSandbox=true): join(sandboxTmpDir, "cwd-<id>")sandboxTmpDir is built from CLAUDE_CODE_TMPDIR and includes a claude-<uid> subdirectory. This works correctly.
  • Non-sandbox path (default): join(os.tmpdir(), "claude-<id>-cwd") — uses bare os.tmpdir() (/tmp), ignoring CLAUDE_CODE_TMPDIR entirely, with no user scoping.

The hex ID is only 4 digits (Math.floor(Math.random()*65536).toString(16).padStart(4,"0")), giving 65,536 possible values. On our server with 9 users, we have 2,392 accumulated files and collisions are routine.

Other temp paths (e.g. the Fm() helper function) correctly respect CLAUDE_CODE_TMPDIR and include user scoping via claude-<uid> subdirectories.

Suggested fix

The non-sandbox CWD file path should use CLAUDE_CODE_TMPDIR and include user scoping, consistent with how other temp paths are handled:

// Current (broken for non-sandbox)
cwdFilePath = join(tmpdir(), `claude-${id}-cwd`)

// Suggested fix
cwdFilePath = join(process.env.CLAUDE_CODE_TMPDIR || tmpdir(), `claude-${process.getuid()}-claude-${id}-cwd`)

Or reuse the existing Fm() helper that already handles this correctly.

Environment

  • Claude Code version: 2.1.68
  • OS: Debian Linux 6.1.0-40-amd64 (shared server, 9 users)
  • CLAUDE_CODE_TMPDIR=/var/tmp/claude (set but not respected for CWD files)

Additional context

Full analysis with source code references: https://gist.github.com/ShonaDouglasKT/e00d60776bd69a91b4a97ca62fe06545

Metadata

Metadata

Assignees

No one assigned

    Labels

    duplicateThis issue or pull request already exists

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions