[BUG] Interrupted global auto-update (macOS/npm) leaves broken half-install: orphaned staging symlink + missing native optional dep, no rollback → `claude: command not found`

Open 💬 0 comments Opened Jul 11, 2026 by LovelyCookie

Summary

A background auto-update of the global npm install on macOS was interrupted partway through and left the install in a broken half-state with no rollback: the claude command disappeared entirely (command not found), because (a) the final symlink rename never completed and (b) the platform-native optional dependency (@anthropic-ai/claude-code-darwin-arm64, ~241 MB) was never downloaded. The user had a working claude earlier the same day; the only thing that changed was the auto-update firing for the newly-published 2.1.207.

Related but distinct: #65093 (transient network loss → stuck "Auto-update failed" banner) — that one is Windows-native and about the banner state; this one is macOS global-npm and about a non-recoverable half-installed package.

Environment

  • OS: macOS (Darwin 25.5.0), arm64
  • Node: v26.0.0 · npm: 11.15.0
  • Install method: global npm (installMethod: global), prefix /opt/homebrew
  • Package: @anthropic-ai/claude-code, updating to 2.1.207 (published 2026-07-10T22:25Z)

Symptom

$ claude
zsh: command not found: claude

which -a claude → nothing. Earlier the same day claude worked normally.

Broken state found on disk

  1. Orphaned staging symlink, no final claude: /opt/homebrew/bin/ contained only a temp npm staging link and no claude:

``
lrwxr-xr-x .claude-WV2akNWU -> ../lib/node_modules/@anthropic-ai/claude-code/bin/claude.exe
``
(i.e. npm's stage-then-rename never reached the rename step.)

  1. Native optional dependency missing: @anthropic-ai/claude-code-darwin-arm64 was not installed anywhere. After manually recreating the claude symlink, running it produced:

``
Error: claude native binary not installed.
Either postinstall did not run (--ignore-scripts, some pnpm configs)
or the platform-native optional dependency was not downloaded (--omit=optional).
`
The JS fallback (
cli-wrapper.cjs) also failed for the same reason (Could not find native binary package "@anthropic-ai/claude-code-darwin-arm64"`).

Root cause (analysis)

Three design properties combine so that a single interrupted download leaves the CLI completely non-functional with no fallback:

  1. The real engine is a large "optional" dependency fetched at postinstall. The installed claude is a small launcher shim; the actual ~241 MB native binary is a separate optional dependency. In npm, optional-dependency download failures are silent — npm reports the install as succeeded even though the package cannot run.
  2. The global swap is not atomic. npm stages new files under a temp name (.claude-XXXXXXXX) and renames to claude as the last step. An interruption between staging and rename leaves an orphaned temp symlink and no claude at all — rather than leaving the previously-working version in place.
  3. No rollback + unattended. The update runs in the background, so a transient failure (network drop mid-241 MB download, machine sleep, or the triggering terminal being closed) is neither retried nor surfaced; the previously-working install is already gone. The user only discovers it later as command not found.

Reproduction (conceptual)

  1. Have a working global npm install of claude-code on macOS arm64.
  2. Trigger the auto-update to a new version (or npm install -g @anthropic-ai/claude-code@latest).
  3. Interrupt it during the native-binary download / before the final symlink rename (kill the process, drop the network, or sleep the machine).
  4. Result: claude: command not found, an orphaned /opt/homebrew/bin/.claude-* staging symlink, and a missing @anthropic-ai/claude-code-darwin-arm64. No automatic recovery on next shell.

Workaround that fixed it

npm install -g @anthropic-ai/claude-code --include=optional

(Recreating the claude symlink alone is not enough — the native optional dep must be re-fetched.)

Suggested fixes

  • Make the optional-native-dep download a hard failure, or verify the native binary is present at the end of postinstall and fail the install loudly if it isn't, so npm doesn't report success on a non-runnable package.
  • Atomic update / rollback: don't remove the previously-working version until the new one (including the native binary) is fully staged and verified; on failure, restore the prior version.
  • Retry + surface transient download failures during unattended auto-update instead of leaving an orphaned staging symlink.

---
Filed from a Claude Code session after diagnosing and fixing the broken install.

View original on GitHub ↗