anthropics / anthropics/claude-code
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
- Lenguaje dominante
- Python
- Estrellas
- 145k
- Forks
- 23.1k
- Métricas de merge de PR
- Métricas de PR pendientes
Descripción
**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
//tasks/.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//t`: works
- `CLAUDE_CODE_TMPDIR=/Volumes//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).
Guía de contribución
No hay ninguna guía de contribución indexada para este repositorio
Línea de trabajo
Reproduce with the provided headless claude -p command while polling stat -f %l on the output file, comparing the default boot-volume tmp directory with the APFS RAM disk and sparse image cases. Trace the Bash tool's output-file identity check introduced in 2.1.251 and verify that unchanged device/inode metadata survives a transient extra hard link without killing the command or misreporting the output.
Escrito por el modelo de indexación a partir del texto del issue.
Evaluación
- Stack tecnológico
- bash, macos
- Área
- cli, operating-systems, security
- Tipo de issue
- Error
- Dificultad
- 4/5
- Tiempo estimado
- 3-5 días
- Estado de actividad
- Activo
- Claridad
- Bastante claro
- Aptitud para principiantes
- 55/100