- chenyz2026-08-1017521
github.com/anthropics/claude-code
[BUG] Native updater on Windows silently skips the binary swap when consecutive releases have identical file sizes, and reports success
已打开 01:14PM - 09 Aug 26 UTC

AymanQ-A-Maani
bug
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?```
The Windows native updater decides whether the installed launcher already matches
the new build by comparing FILE SIZE ONLY. When two consecutive releases happen to
compile to the exact same byte size, it concludes the launcher is already up to date,
skips the copy entirely, and returns a result the rest of the update pipeline cannot
distinguish from a real success.The result:
claude updateprints "Successfully updated from 2.1.225 to version 2.1.226",
writes"outcome":"success"with"error_code":nullto ~/.claude/.last-update-result.json,
and leaves the launcher completely untouched.claude --versionstill reports the old
version. Every subsequentclaude updaterepeats the identical false success forever.This hit the 2.1.225 -> 2.1.226 pair, which are byte-identical in size:
2.1.223 280,233,632 bytes
2.1.224 284,981,920 bytes
2.1.225 287,053,472 bytes
2.1.226 287,053,472 bytes <-- same size as 2.1.225, different binaryMD5 2.1.225 f7ad3f8bb03a3f54f96910126c91191e
MD5 2.1.226 04df2e354071833ad36016e62cec7639The staged build in ~/.local/share/claude/versions/2.1.226 was downloaded correctly.
Only the activation step (copying it over ~/.local/bin/claude.exe) was skipped.The false success is the worse half of this bug. A visible failure would be a minor
annoyance; reporting success while doing nothing defeats every diagnostic path at once —
the user-facing message, the update-result record, and the telemetry event
(tengu_native_update_complete / tengu_native_auto_updater_success) all say it worked.
These failures are therefore almost certainly being counted as successful updates in
your metrics, so the true failure rate is invisible.Note:
claude update --forcedoes NOT help — the force flag controls download/reinstall,
not the activation step where the size check lives.claude doctordoes not surface it either.
``### What Should Happen?``
claude updateshould either actually replace the launcher with the new build, or
report a failure. It should never report success while leaving the old binary in place.Specifically:
1. Equal file size must not be treated as proof of equal content. Compare a content
hash, or compare the launcher's reported version against the target version, or
simply always perform the swap.
2. After activation, verify the launcher actually resolves to the target version and
fail loudly if it does not. This single check would have caught the bug regardless
of its cause, and would catch any future activation failure too.
3. The skip path should emit its own telemetry outcome instead of being folded into
the success count.
``### Error Messages/Logs``shell
There is no error — that is the bug. For completeness:Terminal output of the failed update:
Current version: 2.1.225
Checking for updates to latest version...
Updating to 2.1.226...
Successfully updated from 2.1.225 to version 2.1.226Immediately afterwards:
claude --version
2.1.225 (Claude Code)
~/.claude/.last-update-result.json written by that run:
{"timestamp":"2026-08-09T11:58:51.050Z","path":"native","outcome":"success",
"status":"success","version_from":"2.1.225","version_to":"2.1.226","error_code":null}
``### Steps to Reproduce``
1. On Windows with a native install, be on version A.
2. Have version B released where sizeof(B) == sizeof(A) but B != A.
(Real-world instance: A = 2.1.225, B = 2.1.226, both exactly 287,053,472 bytes.)
3. Runclaude update.
-> It prints "Successfully updated from A to version B".
4. Runclaude --version.
-> Still reports A.
5. Confirm ~/.local/share/claude/versions/B exists and is the correct new binary,
while ~/.local/bin/claude.exe still hashes identical to versions/A.
6. Repeat step 3 any number of times — identical false success every time.Root cause, from the Windows branch of the launcher-activation function in the
shipped 2.1.226 binary (minified):async function fTS(e, t) {
if (Sxe().startsWith("win32")) try {
let s = aS.dirname(e);
await gf.mkdir(s, { recursive: !0 });
let a;
try { a = await gf.stat(e) } catch {}
if (a) {
try {
let c = await gf.stat(t);
if (a.size === c.size) return "noop"; // <-- BUG
} catch {}
let l =${e}.old.${Date.now()};
await gf.rename(e, l);
try {
await gf.copyFile(t, e);
try { await gf.unlink(l) } catch {}
} catch (c) { / restore / }
}
...
return "updated"
} catch (s) { return "failed" }eis the launcher path,tis the staged new build.a.size === c.sizetreats equal
file size as proof of equal content and returns "noop" before the rename-and-copy runs.The caller cannot tell "noop" from success:
let l = await fTS(o, n);
if (l !== "updated" && !await VKt(o)) { ...throw... }
return { wasNewInstall: s, moveRetried: a,
activationFailed: l === "failed",
activationRefused: l === "refused" };With l === "noop" the launcher still exists and is a valid executable, so VKt(o) is
truthy and nothing is thrown. activationFailed and activationRefused are both false.
The caller returns {success: true, latestVersion: l}, logs "Successfully updated to
version ...", which becomes wasUpdated: true and the "outcome":"success" record.The surrounding code already distinguishes "failed" and "refused" outcomes and has a
rich error classifier including swap_failure and av_quarantine categories — the "noop"
path bypasses all of it.
```### Claude Model_No response_
Is this a regression?
Yes, this worked in a previous version
Last Working Version
2.1.224
Claude Code Version
2.1.226
Platform
Anthropic API
Operating System
Windows
Terminal/Shell
VS Code integrated terminal
Additional Information```
Antivirus ruled out
Including this because AV is the natural first suspicion for a Windows file-replacement
failure. Kaspersky is installed on this machine. It is not involved:1. No file operation is ever attempted. The function returns "noop" before the
rename/copy, so there is nothing for AV to block.
2. The same operations succeed manually. Renaming the RUNNING claude.exe and copying
the 287 MB staged build over it both completed without error, with Kaspersky active.
(Renaming a running executable is permitted here, so the exe-lock path is not
implicated either.)
3. The product's own AV detection never fired — error_code was null and the outcome
was "success", not "av_quarantine".Is it really a regression?
Probably not in the code. The size-only shortcut appears in both 2.1.225 and 2.1.226,
and updates 2.1.223 -> 2.1.224 -> 2.1.225 all applied correctly because those builds
differed in size. So this looks like a long-standing latent bug that the 2.1.225/2.1.226
size collision triggered for the first time, rather than something newly introduced.
I answered the regression question as "yes" because updating did work for me previously,
but the underlying defect is likely older than 2.1.225.Scope
Any Windows native-install user whose installed version happens to match the byte size
of the next release will be silently pinned to their current version indefinitely, with
the CLI insisting the update succeeded. Since the size collision is a coincidence, the
affected population will look random and intermittent from the outside, which will make
it hard to correlate from telemetry — especially as these runs are recorded as successes.Workaround for affected users
Copying the staged build over the launcher by hand restores the correct version:
mv ~/.local/bin/claude.exe ~/.local/bin/claude.exe.bak
cp ~/.local/share/claude/versions/<target> ~/.local/bin/claude.exe
claude --version # verifyAlternatively, removing the launcher entirely before updating takes the else-branch
(copyFile with no size check) and applies correctly.
```原来真是bug,225升226是假替换,但是显示成功,还以为CC Switch的bug呢主楼 - dragon_from_east2026-08-1023908
你用的是啥模型,咋会这样呢?是CC订阅的吗
- mawai2026-08-1010417
我记得之前好像也有过update成功后还是老版本
- chenyz2026-08-1017521
我的意思是,我用命令升级,提示升级226成功,但是cc switch还是显示225 ^-^
- gamecrafters2026-08-105720
正常,上次我claude update时提示的是225,但是实际展示的是226,应该是版本号写错了
- dragon_from_east2026-08-1023908
重启下看看,你CC的号是官方订阅的吗?还是用中转的吗
- Soare022026-08-1020355
有两个claudecode吧,一个原生版本,就是官方那个irm的和npm安装的,这两个版本好像会同时存在而且可以版本不同,你让AI检查一下是否有2个版本。