`claude update` reports success but installs the Bun runtime as Claude Code (binary swapped for `bun`)

Status Open
Reported on v2.1.219
Maintainer reply None cached
Activity 0 comments · opened Jul 24, 2026

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 claude CLI 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.2182.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)

  1. First claude update: versions/2.1.219 landed as a zero-filled sparse file (24 KB actual on disk, 275 MB apparent; filedata; launching gave Exec format error). Result recorded as success.
  2. Second claude update (~30 min later): versions/2.1.219 re-downloaded as a complete, valid Bun v1.4.0 binary (not Claude Code). Result again recorded as success. The claude symlink was pointed at it, so running claude ran bun.

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 --version reports the requested version with the (Claude Code) marker) before repointing the launcher symlink and recording success.

Actual behavior

  • The Bun runtime was installed as 2.1.219, the launcher was repointed to it, and the update was recorded as success — 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

  1. How did the Bun runtime end up published in the 2.1.219 version slot for this platform/channel? (Build-pipeline artifact mixup? CDN/mirror serving the wrong object?)
  2. Can the updater add post-download integrity verification (checksum/signature, or a --version sanity check for the (Claude Code) marker) before it repoints the launcher and records success?
  3. Is 2.1.219 affected 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. 🙂

View original on GitHub ↗