[BUG] v2.1.150 darwin-arm64: npm install silently truncates native binary (~213 MB → ~63 MB), causing "killed" on launch and auto-update infinite loop
Preflight Checklist
- [x] I have searched existing issues and this hasn't been reported yet
- [x] This is a single bug report (please file separate reports for different bugs)
- [x] I am using the latest version of Claude Code
What's Wrong?
## Summary
On macOS arm64, npm install -g @anthropic-ai/claude-code (and the same install triggered internally by
Claude Code's auto-updater) silently truncates the native binary at
node_modules/@anthropic-ai/claude-code-darwin-arm64/claude to roughly 30% of its real size. The launched
binary is immediately killed by the kernel (zsh: killed claude). Direct download of the same tarball via
curl and extraction via tar produces a complete, valid binary — so the bug is in npm's extraction path,
not the upstream tarball.
The broken state also triggers an infinite auto-update loop: Claude Code's internal self-heal detects the
corrupt binary, spawns npm install, which fails the same way, and the cycle repeats — spawning long-lived
stuck npm install subprocesses (parent PID = the claude session).
What Should Happen?
Claude should update normally. There appears to be a fatal error in the npm.
Error Messages/Logs
## Symptoms observed
1. `claude doctor` (or any `claude` invocation) prints `zsh: killed claude` and exits.
2. `bin/claude.exe` is much smaller than it should be — observed sizes during failure: 500 B (postinstall
stub), 5.8 MB, 6 MB, 53 MB, 63 MB, 73 MB. Correct size is **213,070,752 bytes (~213 MB)**.
3. `codesign -v bin/claude.exe` → `main executable failed strict validation`
4. `codesign -dv bin/claude.exe` → `code object is not signed at all`
5. `node_modules/@anthropic-ai/claude-code-darwin-arm64/` contains the binary but is **missing
`package.json`** after extraction, even though the upstream tarball does include it. This causes the
postinstall script's `require.resolve('@anthropic-ai/claude-code-darwin-arm64/package.json')` to fail with
`MODULE_NOT_FOUND`.
6. While the install is in this broken state, multiple long-lived `npm install
@anthropic-ai/claude-code@2.1.150` subprocesses accumulate, all with PPID = the running `claude` process
(auto-update retry loop).
7. npm's atomic-rename swap targets a deterministic staging dir name (`.claude-code-2DTsDk1V`), which
collides on every retry → `ENOTEMPTY` errors.
## Confirmation that the upstream tarball is fine
curl -sSL -o tarball.tgz \
https://registry.npmjs.org/@anthropic-ai/claude-code-darwin-arm64/-/claude-code-darwin-arm64-2.1.150.tgz
tar -xzf tarball.tgz
ls -la package/claude # → 213,070,752 bytes (~213 MB)
codesign -v package/claude # exit 0
codesign -dv package/claude # Identifier=com.anthropic.claude-code, TeamIdentifier=Q6L2SF6YDW, hardened
runtime
ls package/package.json # exists
Installing the binary from this tar-extracted directory restores a fully working Claude Code.
Steps to Reproduce
This cascade of errors was caused by "auto-update".
Claude Model
Other
Is this a regression?
Yes, this worked in a previous version
Last Working Version
_No response_
Claude Code Version
This is: 2.1.150
Platform
Anthropic API
Operating System
macOS
Terminal/Shell
Terminal.app (macOS)
Additional Information
Suggested investigation
- Why does npm's tar extraction on this platform/version combination drop the latter ~70% of the binary file
and omit package.json? Possible angles: streaming-extraction interaction with the ~213 MB binary size,
file-descriptor limits, an npm tarball-handler bug specific to npm-on-arm64-Homebrew, or an issue with how
npm handles multi-byte/binary files in tarballs above a size threshold.
- Consider adding a post-extraction integrity check to install.cjs: if statSync(src).size !== expectedSize or
codesign -v src fails, abort the install with a clear error rather than placing a corrupt binary at
bin/claude.exe. This would prevent the auto-update infinite loop.
- The deterministic staging-dir name causing collision-on-retry (ENOTEMPTY) is independently worth fixing —
it makes recovery harder.
This issue has 2 comments on GitHub. Read the full discussion on GitHub ↗