Skip to content

Stop update checks from replacing a downloaded update before Relaunch installs it - #2312

Open
patleeman wants to merge 3 commits into
get-bb:mainfrom
patleeman:fix/nightly-update-staging-invalidation
Open

Stop update checks from replacing a downloaded update before Relaunch installs it#2312
patleeman wants to merge 3 commits into
get-bb:mainfrom
patleeman:fix/nightly-update-staging-invalidation

Conversation

@patleeman

@patleeman patleeman commented Aug 23, 2026

Copy link
Copy Markdown
Contributor

What was wrong

On macOS, every desktop update check made Squirrel.Mac discard its finished update.<id> staging directory and start a fresh, partial extraction for the next fetch — while the Settings UI kept offering Relaunch. The check paths were: the unthrottled check on every Settings → Updates page visit (BB_DESKTOP_CHECK_FOR_UPDATES_CHANNEL), the 15-minute activity check, and the hourly timer. A Relaunch clicked after any of these re-checks handed ShipIt install instructions pointing at a directory that did not yet contain bb Nightly.app. ShipIt retried three times, logged Failed to copy bundle … No such file or directory, aborted the update, and relaunched the old build. Net effect: nightly updates downloaded forever and never applied.

Observed live on an affected machine: the app quit cleanly on Relaunch (owned-runtime children stopped, main process exited), then ShipIt immediately failed three times against the newest staging dir while an older, complete staging had been discarded minutes earlier.

What changed

  • apps/desktop/src/desktop-auto-update.ts: once electron-updater reports the update downloaded, checkForUpdates() and therefore checkAfterActive() return the held state instead of hitting the updater, so nothing restages or invalidates the pending ShipIt install until it is applied.
  • apps/desktop/test/desktop-auto-update.test.ts: regression test asserting no further updater checks run while an update is downloaded (including after the activity-check throttle window passes) and the downloaded state is preserved.

No wire-format changes; no HOST_DAEMON_PROTOCOL_VERSION bump needed.

How you verified

  • New test fails without the guard (checks keep incrementing and state gets restaged) and passes with it.
  • pnpm exec turbo run test --filter=@bb/desktop --force — all 4 tasks green.
  • pnpm exec turbo run typecheck --filter=@bb/desktop --force — green.
  • Manual QA on the affected machine: confirmed via ShipIt stderr log that the failure mode matched the diagnosis (Installation error: … Failed to copy bundle … No such file or directory, ×3, abort); with a complete staging left undisturbed and the app quit normally, ShipIt logged Installation completed successfully and the app came up on the new version.

AGENT GENERATED

… staging

Every update check (Settings page visits, the 15-minute activity check,
and the hourly timer) made Squirrel replace its finished update.<id>
staging directory with a fresh partial extraction while the UI still
offered Relaunch. Clicking Relaunch then handed ShipIt a directory
without bb Nightly.app, ShipIt aborted after three retries, and the old
build relaunched - so nightly updates never applied.

Once electron-updater reports an update downloaded, skip further checks
until that install is applied.
@patleeman patleeman changed the title Hold a downloaded desktop update against re-checks that tear down its staging Stop update checks from replacing a downloaded update before Relaunch installs it Aug 23, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant