Why Your Electron Auto-Update Silently Fails (And How to Catch It Before Your Users Do)
Most Electron apps have broken auto-update flows and the developers don't know it.
I've audited dozens of Electron apps using electron-updater and the same three bugs appear in almost every codebase. Here's what they are and how to fix them.
1. The "update-downloaded" event fires but the app never restarts
This happens when you call autoUpdater.quitAndInstall() without the isSilent and isForceRunAfter parameters on Windows. The installer runs, but Windows doesn't relaunch your app because the default NSIS behavior is to wait for user interaction.
Fix:
autoUpdater.quitAndInstall(true, true);
// isSilent = true → no installer UI
// isForceRunAfter = true → relaunches your app after install2. Differential updates fail silently on macOS
If your macOS build uses hardenedRuntime: true (which it should for notarization) but you're generating blockmap files with an older version of electron-builder, the differential download will fail and fall back to a full download every time. Your users are downloading 150MB instead of 5MB and you'd never know unless you're monitoring download sizes.
How to detect it:
autoUpdater.on('download-progress', (progress) => {
console.log(`Downloading: ${progress.transferred} / ${progress.total}`);
// If total ≈ your full app size, differentials are broken
});Fix: Upgrade electron-builder to 24.x+ and regenerate your blockmaps. Verify the blockmap hash matches your published release.
3. No rollback when the update corrupts the app
electron-updater has no built-in rollback mechanism. If a bad update ships and the app crashes on launch, your users are stuck in a crash loop with no way to recover except manually reinstalling.
The pattern I teach:
// In your main process entry point
const launchCount = store.get('launch_count_since_update', 0);
if (launchCount < 3) {
store.set('launch_count_since_update', launchCount + 1);
// App survived 3 launches = update is stable
} else {
store.set('last_stable_version', app.getVersion());
}Combine this with a health-check IPC ping from your renderer. If the renderer doesn't respond within 10 seconds of launch, trigger a rollback to the last known stable version stored in your update server.
---
These three issues affect the majority of Electron apps in production. The scary part is they're all silent failures — your error tracking won't catch them because the app doesn't crash, it just doesn't update properly.
I built a full course on testing every stage of this pipeline with Cypress component tests so you catch these issues in CI before they reach your users. If you're shipping an Electron app to real users, this is the gap in your workflow.
