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

オープン
#92,586 コメント 1 件 リアクション 0 件 担当者 0 名 GitHub で見る
area:bash area:sandbox bug has repro platform:macos
主要言語
Python
スター
145k
フォーク
23.1k
PR マージ指標
PR 指標を取得中

説明

**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).

コントリビューションガイド

このリポジトリのコントリビューションガイドは索引されていません

調査の方向性

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.

索引モデルが issue の本文から書いたものです。

評価

技術スタック
bash, macos
領域
cli, operating-systems, security
issue の種類
バグ
難易度
4/5
見積もり時間
3〜5日
活発さ
活発
明瞭さ
おおむね明確
初心者へのやさしさ
55/100

新しい issue をメールで受け取る

初心者向けの GitHub issue を短くまとめたダイジェスト。