[Bug] Transient network loss is recorded as a persistent install_failed; "Auto-update failed" banner never clears after reconnect (Windows native, already on latest)
Preflight Checklist
- [x] I have searched existing issues and this specific combination hasn't been reported. Related: #62130 (same root cause: a transient check failure surfaced as an install failure on an already-current install), #64554 / #64292 (doctor/banner mismatch; #64292 also shows a network socket error), #61676 (Windows auto-updater regression from the 2.1.147 rework), #56189 (persistent un-suppressible banner).
- [x] This is a single bug report.
- [x] I am using the latest version of Claude Code.
What's Wrong?
If network connectivity drops while a Claude Code session is running (e.g. Disable the Ethernet adapter, Windows 10), the background auto-update check fails and the CLI shows:
✗ Auto-update failed · Run /doctor
The problem is not the failure itself but that the failed state is sticky:
- The banner never clears after connectivity is restored — it keeps appearing on every startup.
- Running
/doctordoes not clear it;/doctorreportsLast update attempt: failed (install_failed). - Crucially, the install is a healthy native install already on the latest channel version (
Currently running: native (2.1.161),Latest version: 2.1.161, channellatest). There was nothing to install — so a transient network/check failure is being (a) misclassified asinstall_failedand (b) persisted indefinitely without ever being reset on the next successful check or when the network comes back.
This is the same root cause as #62130 (transient check surfaced as install failure) but on Windows native, with a clean deterministic trigger and the added problem that the failed state is persisted and never reset.
What Should Happen?
- Distinguish a transient network / check failure from a real install failure (cf. #62130); a benign check failure should retry silently, not raise the red banner.
- When the installed version already equals the channel target (nothing to do), never show "Auto-update failed".
- The failed state must be reset on the next successful check / when connectivity returns, and
/doctorshould clear it (or at least offer an action to re-check), so the banner does not persist forever.
Error Messages/Logs
/doctor output (sanitized) while the banner was stuck, after the network had been restored:
Diagnostics
Currently running: native (2.1.161)
Commit: 6a550aea7c74
Platform: win32-x64
Config install method: native
Updates
Auto-updates: enabled
Auto-update channel: latest
Last update attempt: failed (install_failed) — 2026-06-03
Stable version: 2.1.150
Latest version: 2.1.161
Note: Currently running already equals Latest version (2.1.161), so no install was actually pending — yet the last attempt is recorded as install_failed.
Steps to Reproduce
- Native install on Windows 10, auto-update channel
latest, already on the latest published version. - Start a Claude Code session.
- While the session is running, disable the network adapter (e.g. Disable the Ethernet NIC).
- On the next background update cycle the banner
✗ Auto-update failed · Run /doctorappears. - Re-enable the network adapter → the banner stays.
- Run
/doctor→ it reportsLast update attempt: failed (install_failed)and does not clear the state; the banner keeps appearing on every startup.
Is this a regression?
Yes (perceived) — this did not happen on earlier versions; it started a few releases ago. Timing is consistent with the auto-updater rework noted in the 2.1.147 changelog and in #61676.
Last Working Version
Unknown (a few versions ago).
Claude Code Version
2.1.161 (Claude Code)
Platform
Claude Pro/Max (CLI)
Operating System
Windows 10 Pro 10.0.19045 (win32-x64)
Terminal/Shell
PowerShell
Additional Information
Reproducible on demand by toggling the NIC, which makes this a clean repro for the "transient check failure persisted as install_failed" class of bugs (#62130, #64554, #64292).
Showing cached comments. Read the full discussion on GitHub ↗
3 Comments
Confirming on macOS (darwin-arm64) — and a data point that rules network out as the trigger
Seeing this exact sticky
install_failedbanner on macOS native, so it isn't Windows-specific. More importantly, in my case there is no network involvement at all — it reproduces on a healthy connection, which suggests the "transient network/check failure" framing is too narrow: there appears to be a code path that throws on the already-on-latest run itself.Environment
2.1.177(native installer),darwin-arm64, macOS 26.5.1 (build 25F80 / Darwin 25.5.0)latest;Currently running==Latest version==2.1.177(nothing to install)installMethod: native,autoUpdatesProtectedForNative: true. Independent of theautoUpdatesflag — it failed identically while that flag wasfalse(6-13, 6-14) and after flipping it totrue(6-15).Symptom — identical to this issue:
✗ Auto-update failed · Run /doctor, sticky across restarts.It recurs ~once per day, deterministically, on a full connection.
~/.claude/.last-update-result.jsonwas rewritten on three consecutive days, byte-identical except the timestamp:(2026-06-13, -14, -15 — all while already on 2.1.177, the latest.)
What I ruled out (so it's not environment, and not network):
latestchannel and…/2.1.177/manifest.jsonboth fetch fine (HTTP 200); the publisheddarwin-arm64size/checksum match the installed binary exactly.versions/,staging/, and the lock dir are all clean (staging empty, no stale locks).claude updatesucceeds every time →Claude Code is up to date (2.1.177), and notably does not write.last-update-result.json.Root-cause mechanism (from the 2.1.177 bundle). The native updater records its result like this:
Two things fall out of this and together explain the "never clears" behavior:
install_failed. Any earlier failure is sticky until a real update lands or the file is removed by hand. (This is the persistence half of the bug.)version_to: nullanderror_code: null(so it threw before resolving a target, and it's none of the categorized cases: exe-lock / restore-failed / env-setup). The thrown message only goes toN(…, {level:"error"})and isn't persisted anywhere I could find, so I can't capture the exact exception from outside the process — but with network/manifest/disk/locks all healthy and manual update working, the throw looks intrinsic to the background already-latest path rather than a transient external failure.Net: the two fixes requested in this issue would cover the macOS case too — (a) never record/show
install_failedwhencurrent == latest(nothing to install), and (b) reset the persisted state on the next successful or up-to-date check, not only on a real update. It would also help to surface that caughtNative auto-updater failed: …message in a durable debug log so the underlying throw can actually be diagnosed.Happy to provide
/doctoroutput or anything else useful.Confirming the same misclassification + never-reset behavior on Linux (no network loss involved) — this is not Windows- or connectivity-specific.
Environment
6.12.94+deb13-amd64~/.local/share/claude/versions/, symlink from~/.local/bin/claude), channellatestSymptom
/doctorhas shownLast update attempt: failed (install_failed)persistently across many versions (first noticed around 2.1.191), while updates actually land successfully every day:Staging dir clean, no locks, symlink correct — install is healthy and on latest.
The stale record
~/.claude/.last-update-result.jsonat the time /doctor reported the failure:version_fromequals the installed latest andversion_toisnull— i.e. a background check that resolved no target version (already up to date) was recorded asinstall_failed. No connectivity outage occurred here, so the trigger differs from the OP's repro, but the failure mode is the same: a check-phase no-op/transient is persisted as an install failure and never reconciled.Manual path doesn't clear it
claude update→Claude Code is up to date (2.1.198), exits clean — and does not rewrite.last-update-result.json, so the stalefailedrecord survives and/doctorkeeps displaying it indefinitely.Suggests the fix shape in the OP holds generally: treat
version_from == latest && version_to == nullas success/no-op, and reset the persisted state on any successful check (including the manual up-to-date path).Still reproducing on 2.1.220 — Windows 10 Pro 10.0.19045 (win32-x64), native install, channel
latest.Almost two months and many releases after the original report, the signature is unchanged. Current content of
~/.claude/.last-update-result.json:version_to: nullconfirms no install was ever attempted: the check failed (network dropped while the session was running) and the outcome was recorded asinstall_failed. 2.1.220 is already the current version, so there was nothing to install in the first place.Once that record is written it is never reset — the banner survives reconnection, restarts and subsequent successful checks. Neither
claude doctornorclaude updateclears it; the only way out is deleting~/.claude/.last-update-result.jsonby hand.Newer reports describing the same behaviour: #81898 (false banner on 2.1.220 while already up to date), #82408 (
claude updatedoes not clear the stale record, andclaude doctornever reads that file), #70608 (failed state never self-heals) — in addition to #62130 / #64554 / #64292 already linked in the description.The fix asked for in the original report still stands: do not persist a failed check as
install_failed, and reset the record on the next successful check.