fix(linux-desktop): fix Electron download cache corruption handling on build - #37545
Conversation
hermes desktop failed on Linux with an ENOENT renaming release/linux-unpacked/electron -> Hermes. Root cause is a corrupt cached Electron zip (~/.cache/electron/electron-*.zip): app-builder unpack-electron extracts a partial tree from the bad zip that is missing the electron binary, so electron-builder dies on the final rename. Re-running repeats the broken extraction, leaving the desktop app permanently unlaunchable until the cache is manually purged. - Add _electron_download_cache_dirs() + _purge_corrupt_electron_cache() to hermes_cli/main.py: validate every electron-*.zip via zipfile.testzip() and delete corrupt ones; honor electron_config_cache / ELECTRON_CACHE overrides with per-OS defaults. - Wire purge + single retry into cmd_gui packaged-build failure path so a poisoned download self-heals (electron re-downloads clean). - Add beforePack hook (apps/desktop/scripts/before-pack.cjs) to wipe the target unpacked dir before staging, making packaging idempotent across interrupted runs. Cross-platform, best-effort. - Tests: corrupt-zip detector, cmd_gui purge/retry/launch path, no-retry-when-clean path, and node --test for the cleanup helper.
austinpickett
left a comment
There was a problem hiding this comment.
Approve. Verified against main: apps/desktop/scripts/before-pack.cjs does not exist, package.json has no beforePack hook, and _purge_corrupt_electron_cache/_electron_download_cache_dirs are absent from hermes_cli/main.py. The ENOENT electron->Hermes rename failure on an interrupted/corrupt pack is real and currently unrecoverable without a manual rm -rf.
Two-layer fix is well chosen and independent:
beforePackwipes the staleappOutDirso packaging is idempotent across interrupted runs (best-effort, never throws → never masks the real build).- CLI-side purge of CRC-failing
electron-*.zipcache entries with a single retry, honoringELECTRON_CACHE/electron_config_cache/XDG/platform defaults.
Cross-platform cache resolution is correct, testzip() is the right validation, and the tests cover the happy path, no-op, bad-input, retry-once, and clean-cache-no-retry cases. No notes.
|
Thanks for the detailed reproduction and recovery path. This has already been implemented on
The original |
What does this PR do?
Fixes
hermes desktopfailing to build/launch on Linux (and any platform) when the cached Electron download is corrupt.Running
hermes desktopon Ubuntu 24.04 dies during packaging with:The message looks like a stale-output or permissions problem, but the real root
cause is a corrupt cached Electron zip in the per-user download cache
(
~/.cache/electron/electron-v40.9.3-linux-x64.zip).unzip -ton it fails("86257938 extra bytes … CORRUPT"). electron-builder's
app-builder unpack-electronextracts the distribution from that cached zip (not fromnode_modules/electron); because the zip is malformed, it writes the smallmembers (
LICENSE,.pak,chrome-sandbox) but never the 193 MBelectronbinary, then dies renaming the missing binary to
Hermes. Re-running repeatsthe same broken extraction forever, so the desktop app is permanently
unlaunchable until the user manually deletes a cache file they have no way to
know about.
This is the right approach because it makes
hermes desktopself-heal: validatethe cache, purge corrupt zips, retry once (electron-builder re-downloads a clean
copy). It is narrow, reversible, and adds no behavior change to a working build.
A complementary
beforePackcleanup hook makes packaging idempotent acrossinterrupted runs. Verified empirically: purging the corrupt cache + re-running
produces a working
Hermesbinary; cleaning only the output dir did not.Related Issue
Fixes #37544
Type of Change
Changes Made
hermes_cli/main.py:_electron_download_cache_dirs()— resolve per-OS Electron downloadcache dirs, honoring
electron_config_cache/ELECTRON_CACHEoverrides._purge_corrupt_electron_cache()— validate everyelectron-*.zipvia
zipfile.testzip()(full CRC check) and delete corrupt ones;best-effort, never raises.
cmd_guipackaged-buildfailure path (skips for
--sourcemode).apps/desktop/scripts/before-pack.cjs(new) — electron-builderbeforePackhook that wipes the target unpacked dir before staging, so an interrupted
prior pack can't poison the next run's rename. Cross-platform, best-effort.
apps/desktop/package.json— register"beforePack": "scripts/before-pack.cjs".apps/desktop/scripts/before-pack.test.cjs(new) —node --testcoverage forthe cleanup helper (removes populated dir, no-ops when absent, ignores invalid
input, hook never rejects).
tests/hermes_cli/test_gui_command.py— add tests: corrupt-zip detectorremoves only bad zips / no-ops when valid;
cmd_guipurge→retry→launch path;no-retry-when-clean fail-fast path.
How to Test
⚠ Detected corrupt cached Electron download (N file(s)); removed and retrying build...,the build re-downloads a clean Electron, packages successfully, and launches.
ls -la apps/desktop/release/linux-unpacked/Hermes # 193 MB binary presentChecklist
Code
fix(scope):,feat(scope):, etc.)pytest tests/ -q(viascripts/run_tests.sh tests/hermes_cli/test_gui_command.py) and all tests passDocumentation & Housekeeping
docs/, docstrings) — or N/A (behavior is internal build robustness; helper docstrings document root cause)cli-config.yaml.exampleif I added/changed config keys — N/A (no config keys added)CONTRIBUTING.mdorAGENTS.mdif I changed architecture or workflows — N/A (no architecture/workflow change)beforePackplatform-agnosticFor New Skills
Not applicable — this is a bug fix to the desktop build pipeline.
Screenshots / Logs
Failure (before):
Cache corruption proof:
Recovery (after):