`claude update` reports success but installs the Bun runtime as Claude Code (binary swapped for `bun`)
claude update reports success but installs the Bun runtime as Claude Code (binary swapped for bun)
Summary
On a native Linux install, the auto-updater downloaded the Bun runtime (v1.4.0) and installed it into the version slot as Claude Code 2.1.219, then repointed the claude launcher symlink at it. claude update reported "outcome":"success", but the claude command was now bun. This happened twice from the same update channel within one day.
This is a release-integrity issue: the updater installs a binary that is not Claude Code and reports success, with no post-download verification that the artifact is actually Claude Code.
Severity / impact
- The
claudeCLI is silently replaced with an unrelated binary; Claude Code becomes unusable. - More importantly, an update path that installs a different binary than advertised — while reporting success — is a supply-chain/integrity concern. In this case the artifact was the genuine, unmodified Bun runtime (benign), but the mechanism that allowed the wrong artifact through would equally pass any other binary served into that slot.
Environment
- Claude Code native install (not npm), auto-update path (
"path":"native") - OS: Red Hat Enterprise Linux 9.8, kernel 5.14.0-687.15.1.el9_8, x86_64
- Install location:
~/.local/share/claude/versions/, launcher~/.local/bin/claude(symlink) - Update:
2.1.218→2.1.219
What was installed vs. expected
# The file installed as Claude Code 2.1.219:
$ ~/.local/share/claude/versions/2.1.219 --version
1.4.0
$ ~/.local/share/claude/versions/2.1.219 --revision
1.4.0+f6d0fcd24
$ ~/.local/share/claude/versions/2.1.219 --help
Bun is a fast JavaScript runtime, package manager, bundler, and test runner. (1.4.0+f6d0fcd24)
Usage: bun <command> [...flags] [...args]
...
# A known-good real Claude Code binary, for contrast:
$ ~/.local/share/claude/versions/2.1.218 --version
2.1.218 (Claude Code)
file reports all three version files as ELF 64-bit LSB executable, x86-64 (Claude Code is compiled with Bun, so they share a BuildID) — the distinguishing signal is --version: a real build ends with (Claude Code); the 2.1.219 artifact was raw Bun.
Updater still reported success
~/.claude/.last-update-result.json:
{"timestamp":"2026-07-24T17:49:44.008Z","path":"native","outcome":"success","status":"success","version_from":"2.1.218","version_to":"2.1.219","error_code":null}
{"timestamp":"2026-07-24T18:22:42.979Z","path":"native","outcome":"success","status":"success","version_from":"2.1.218","version_to":"2.1.219","error_code":null}
Timeline (two occurrences)
- First
claude update:versions/2.1.219landed as a zero-filled sparse file (24 KB actual on disk, 275 MB apparent;file→data; launching gaveExec format error). Result recorded as success. - Second
claude update(~30 min later):versions/2.1.219re-downloaded as a complete, valid Bun v1.4.0 binary (not Claude Code). Result again recorded as success. Theclaudesymlink was pointed at it, so runningclauderanbun.
Expected behavior
- The updater should install the Claude Code binary for the target version, or fail loudly.
- After download, it should verify the artifact is the expected Claude Code build (e.g. checksum/signature match, or at minimum that
--versionreports the requested version with the(Claude Code)marker) before repointing the launcher symlink and recordingsuccess.
Actual behavior
- The Bun runtime was installed as
2.1.219, the launcher was repointed to it, and the update was recorded assuccess— both when the download was a truncated sparse file and when it was the wrong (Bun) binary.
Workaround used
# Point the launcher back at the last known-good real Claude Code build:
ln -sfn ~/.local/share/claude/versions/2.1.218 ~/.local/bin/claude
rm -f ~/.local/share/claude/versions/2.1.219 # remove the Bun impostor
# Disable auto-update until fixed:
export DISABLE_AUTOUPDATER=1
# Verify:
claude --version # must end in "(Claude Code)"
Questions for the team
- How did the Bun runtime end up published in the
2.1.219version slot for this platform/channel? (Build-pipeline artifact mixup? CDN/mirror serving the wrong object?) - Can the updater add post-download integrity verification (checksum/signature, or a
--versionsanity check for the(Claude Code)marker) before it repoints the launcher and recordssuccess? - Is
2.1.219affected for other users on the same channel, and does it need to be pulled/re-published?
---
P.S. — semi-seriously: I burned a non-trivial pile of tokens getting Claude Code to work out that Claude Code had quietly turned into a JavaScript runtime. If there's a "diagnosed and reported your own updater bug" rebate, please apply it generously to my invoice. 🙂