Skip to content

Desktop updater: no quit-and-vanish on macOS, no stuck AppImage install, no stale tray checkbox - #1927

Merged
BarganConstantin merged 4 commits into
developmentfrom
fix/desktop-updater
Oct 4, 2026
Merged

BarganConstantin merged 4 commits into
developmentfrom
fix/desktop-updater

Conversation

@BarganConstantin

Copy link
Copy Markdown
Owner

What changes

  • macOS: an app that cannot replace itself no longer quits for an update. A copy run from its disk image, a translocated copy, or one in a folder the account cannot write to used to stage every release and then quit at the next quiet spell into a swap that failed before reopening the app, on every launch. The updater now checks that the app's folder and bundle can be written before it downloads anything, and reports an error that says to move the app instead. If a swap still fails, the script reopens the running version after a restart, removes the download, and notes the release so the next check does not stage it again. A successful swap clears the note.
  • Windows/Linux: a failed background download no longer leaves an unhandled rejection. electron-updater returns the started download as its own promise. Nothing held that promise, so a dropped connection mid-download ended in Electron's modal "A JavaScript error occurred in the main process" box. The failure is still recorded as the update's error state, as before.
  • AppImage: a failed install no longer latches the updater. electron-updater's install() latches on its first call, and only its own quitAndInstall resets it. After one failed install, every later one was silently ignored while the next check said "ready" again, so the quiet install retried about every minute and "Restart to update" did nothing. The updater now resets the latch and reports the failure. An AppImage in a folder the account cannot write to is not offered as ready at all.
  • Tray: a checkbox goes back to the real state when its toggle fails. Electron ticks the native checkbox before the click handler runs. When "Start at login" or "Notifications while closed" then failed, the rebuilt menu matched the one already shown, so the menu was not replaced and the box stayed in the wrong state. A checkbox click now makes the next redraw replace the menu.

Verification

  • npm run typecheck: clean.
  • Full suite (--maxWorkers=3): 844 files, 11376 tests, all passed.
  • New regression tests. Each one was run against the code before its fix and failed for the reason described:
    • desktop-update-unreplaceable-app.test.ts. Before the fix, an app in a read-only folder was staged ("ready"), and a release whose swap had failed was staged again.
    • desktop-updater.test.ts, swap-script cases extended. Before the fix, a failed mv opened nothing and the script did not record the failed release. A failed ditto exited 0 and recorded nothing, and a successful swap left a stale note in place.
    • desktop-update-download-failure.test.ts. Before the fix, one unhandled rejection (net::ERR_NETWORK_CHANGED) reached the process on both linux and win32.
    • desktop-update-appimage-failed-install.test.ts. Before the fix, the second install was ignored (1 attempt instead of 2) and the state stayed "ready". An unwritable AppImage location was also reported as "ready".
    • desktop-tray-checkbox-revert.test.ts. Before the fix, the checkbox stayed ticked after a failed toggle.
  • The new read-only-folder case is registered in skip-gates.mjs. The Windows skip total in publish.yml and in skip-gate-inventory.test.ts goes from 53 to 54.
  • No UI change, so no browser check. Electron and the updater were never started. Everything ran against fakes.

An app run from its disk image, a translocated copy, or one in a folder the
account cannot write to staged every release, then quit at the next quiet
spell into a swap that failed before it reopened the app. Such an app now
stages nothing and says why. A swap that fails still reopens the running
version after a restart and throws the download away, and the release it
could not put in place is not staged again.
electron-updater hands a started download back from checkForUpdates, and
that promise rejects when the download fails, after the error listener has
already recorded it. Nothing held it, so a dropped connection mid-download
ended in Electron's modal main-process error box on Windows and Linux.
electron-updater latches install() on its first call and only its own
quitAndInstall releases it, so after one failed AppImage install every later
one was ignored while the next check said ready again, and the quiet install
retried every minute for nothing. The updater now releases the latch and
reports the failure, and an AppImage in a folder this account cannot write
to is not offered as ready.
Electron ticks a checkbox in the native menu before the row's handler runs.
When Start at login or Notifications while closed then failed, the next
template matched the one shown, the menu was not replaced, and the box kept
claiming a state that was not true. A checkbox click now makes the next
redraw replace the menu.
@BarganConstantin
BarganConstantin merged commit 4e69604 into development Oct 4, 2026
10 checks passed
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