Skip to content

updater: tolerate read-only module dirs (fixes flatpak boot) - #251

Open
evandrodevbr wants to merge 1 commit into
GooseMod:mainfrom
evandrodevbr:fix/readonly-pending-dir
Open

updater: tolerate read-only module dirs (fixes flatpak boot)#251
evandrodevbr wants to merge 1 commit into
GooseMod:mainfrom
evandrodevbr:fix/readonly-pending-dir

Conversation

@evandrodevbr

@evandrodevbr evandrodevbr commented Aug 6, 2026

Copy link
Copy Markdown

Fixes #244

The problem

On Flatpak, Discord runs with localModulesRoot pointing at /app/discord/modules — a read-only directory inside the sandbox. moduleUpdater.init() creates the pending directory unconditionally, even when SKIP_MODULE_UPDATE is active (which it is here, since the modules are local):

// Purge pending
fs.rmSync(downloadPath, { recursive: true, force: true });
mkdir(downloadPath);

This throws EROFS/ENOENT — and since init() is called from startUpdate(), which runs under app.whenReady().then(startUpdate) with no try/catch at all, the exception aborts the whole startup. Practically speaking: the Discord process starts and stays alive, but no window is ever created — no splash, no renderer. Just an orphan process burning memory.

Observed log (Discord 1.0.152 flatpak, Arch Linux):

(node:7) UnhandledPromiseRejectionWarning: Error: ENOENT: no such file or directory, mkdir '/app/discord/modules/pending'
    at Object.mkdirSync (node:fs:1363:26)
    at mkdir (.../updater/moduleUpdater.js:1:297)
    at exports.init (.../updater/moduleUpdater.js:1:1388)
    at startUpdate (.../bootstrap.js:1:3065)

After fixing the boot crash, the optional module downloads (krisp, game_utils, rpc) also surfaced uncaughtExceptions — createWriteStream had no error handler and tried to write into the same read-only directory.

The fix

Four small, conservative changes:

  1. moduleUpdater.init() — the pending-directory purge/creation is now wrapped in try/catch and only logged. The directory is only useful when modules will be downloaded; on read-only filesystems it is useless anyway.
  2. downloadModule()createWriteStream now has an error handler: instead of an uncaughtException, the failure is logged and the download tracking is finalized properly (with a writeFailed guard to avoid double-counting).
  3. commitManifest() — manifest write guarded against read-only paths.
  4. bootstrap.js — defense in depth: moduleUpdater.init() wrapped in try/catch. An updater failure should never be able to take down the whole app bootstrap.

Testing

Validated on Flatpak (Arch Linux, Discord 1.0.152 + Vencord): Discord boots normally, window created, renderer alive:

[OpenAsar > Modules] Failed to init pending directory Error: ENOENT: no such file or directory, mkdir '/app/discord/modules/pending'
|  renderer-first-paint:        1645.65
|  renderer-full-interactive:   4810.00

The former download uncaughtExceptions became clean logs:

[OpenAsar > Modules] Failed to download discord_krisp [Error: ENOENT: no such file or directory, open '/app/discord/modules/pending/discord_krisp-0.zip']

On writable systems the behavior is unchanged: the pending directory is still created normally and downloads work as before.

moduleUpdater.init() unconditionally purged and created the pending
download directory, throwing EROFS/ENOENT on read-only filesystems
(e.g. Flatpak, where localModulesRoot points at /app). Since the
exception escaped startUpdate()'s promise chain in bootstrap.js, the
entire app failed to boot: no window, no renderer.

- guard the pending-dir setup in init() and log instead of throwing
- guard createWriteStream errors in downloadModule() (previously
  uncaught exceptions when the pending dir cannot be created)
- guard commitManifest() against read-only manifest paths
- wrap moduleUpdater.init() in bootstrap.js so an updater failure can
  never take down the app bootstrap
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.

OpenAsar makes Discord (flatpak) unable to open on Linux

1 participant