Bash tool kills every command after ~5s ("output file was replaced or could no longer be verified") when an EDR transiently hard-links new files

Status Open
Reported on v2.1.263
Maintainer reply None cached
Activity 1 comment · opened Sep 7, 2026

Version: 2.1.263 (also reproduced on 2.1.260). macOS 26.3 (Darwin 25.3.0), Apple Silicon. Genian Insights EDR installed (system extension).

Symptom

Every Bash tool call, foreground or background, sandboxed or with dangerouslyDisableSandbox, dies about 5 seconds after start with exit code 137 and:

Command killed: its output file was replaced or could no longer be verified
<bash output unavailable: output file /private/tmp/claude-501/<project>/<session>/tasks/<id>.output could not be read (unknown). This usually means another Claude Code process in the same project deleted it during startup cleanup.>

Short commands like pwd also fail: the command runs and the output file contains the correct output, but the read-back is reported as failed. No other Claude Code process is active in the project. The Read tool reads the same file fine.

Root cause

The EDR on this machine adds a second hard link to every newly created file on the boot volume for roughly 1 to 8 seconds, then removes it. stat on the task output file shows nlink=2 during that window, then nlink=1. Inode, size, owner, mode and content never change. Claude Code's output-file identity check (introduced in 2.1.251, "a sandboxed command cannot redirect or replace them") treats this state as a replaced file, sends SIGTERM then SIGKILL to the shell, and reports the output as unreadable with error code unknown.

Evidence

  • Polling stat -f %l on any new file (in /tmp, $HOME, ~/.claude, a 0700 dir) shows nlink 1 → 2 → 1 within ~8s. On a separately mounted APFS RAM disk or sparse image, nlink stays 1.
  • A trap inside the shell recorded SIGTERM at exactly +5s from the parent claude process; the loop kept writing after that until SIGKILL.
  • Headless reproduction with claude -p "run: echo hi && sleep 7 && echo alive" --allowedTools 'Bash(echo:*)':
  • default tmp dir: killed, 137
  • CLAUDE_CODE_TMPDIR=~/cctmp (boot volume, 0700): killed, 137
  • CLAUDE_CODE_TMPDIR=/Volumes/<apfs-ramdisk>/t: works
  • CLAUDE_CODE_TMPDIR=/Volumes/<apfs-sparseimage>/t: works

Expected

A transient extra hard link with unchanged dev/inode is not a replaced file. The check should compare device and inode (and possibly owner/mode) rather than failing on nlink > 1, or at least retry before killing the command. The error message blaming "another Claude Code process ... startup cleanup" is misleading here.

Workaround

Point CLAUDE_CODE_TMPDIR at a directory on a separately mounted volume (settings.json env works).

View original on GitHub ↗

This issue has 1 comment on GitHub. Read the full discussion on GitHub ↗