fix(electron): swallow auto-updater check rejection to avoid unhandled rejection (#3339)

checkForUpdates() is fired unawaited from a setTimeout at startup. The
underlying autoUpdater.checkForUpdates() rejects on a 404 (release update
manifest not published yet), offline, or rate-limit — and the uncaught
rejection surfaced as an "Unhandled Rejection", which the packaged-app smoke
test treats as fatal (failed the macOS-intel v3.8.13 build; passed elsewhere
only by timing race). The autoUpdater "error" event still notifies the user;
wrap the await so the promise rejection never escapes. Adds a regression test.
This commit is contained in:
Diego Rodrigues de Sa e Souza
2026-06-06 21:42:30 -03:00
committed by GitHub
parent df2379053e
commit 630baa6c18
2 changed files with 42 additions and 1 deletions

View File

@@ -266,7 +266,18 @@ async function checkForUpdates(silent = false) {
}
return;
}
await autoUpdater.checkForUpdates();
// Update-check failures (404 when the release manifest isn't published yet,
// offline, rate-limited) are surfaced to the user via the autoUpdater "error"
// event handler. The promise returned by checkForUpdates() ALSO rejects on
// those, so it must be caught here — the startup check (line ~928) fires it
// unawaited inside a setTimeout, and an uncaught rejection there becomes an
// "Unhandled Rejection" that the packaged-app smoke test treats as fatal.
try {
await autoUpdater.checkForUpdates();
} catch (err) {
const msg = err instanceof Error ? err.message : String(err);
console.warn("[Electron] Update check failed (non-fatal):", msg);
}
}
async function downloadUpdate() {

View File

@@ -76,6 +76,36 @@ describe("Electron packaging manifest completeness (#3292)", () => {
}
});
// ─── Auto-updater unhandled-rejection guard (v3.8.13) ────────
//
// checkForUpdates() is fired unawaited from a setTimeout at startup. The
// underlying autoUpdater.checkForUpdates() rejects on a 404 (no published
// update manifest yet), offline, or rate-limit — and an uncaught rejection
// there surfaces as an "Unhandled Rejection" that the packaged-app smoke test
// treats as fatal (it failed the macOS-intel build for v3.8.13). The call must
// be wrapped so the rejection never escapes.
describe("Electron auto-updater rejection handling (v3.8.13)", () => {
const mainSrc = readFileSync(join(import.meta.dirname, "../../electron/main.js"), "utf8");
it("wraps autoUpdater.checkForUpdates() so a 404/offline check can't become an unhandled rejection", () => {
const fn = mainSrc.match(/async function checkForUpdates\([\s\S]*?\n}/);
assert.ok(fn, "checkForUpdates function should exist in electron/main.js");
const body = fn![0];
assert.match(body, /try\s*\{/, "checkForUpdates must wrap the update check in try/catch");
assert.match(
body,
/catch\s*\([\s\S]*?\)\s*\{/,
"checkForUpdates must catch the rejecting autoUpdater.checkForUpdates() call"
);
assert.match(
body,
/try[\s\S]*await autoUpdater\.checkForUpdates\(\)[\s\S]*catch/,
"autoUpdater.checkForUpdates() must sit inside the try block"
);
});
});
// ─── URL Validation Tests ────────────────────────────────────
describe("Electron URL Validation", () => {