Hi, my Griply crashes on disconnect when using a hotspot. I caught the stack trace by running the app in the terminal.
Here is Claude’s analysis on the fix. Looks easy. Thanks!
What makes the last disconnection different
Look at the timestamps:
every hourly update check before 05:58 actually
succeeded
("Update for version 2.3.0 is not available …"). The
ECONNRESET
/
ETIMEDOUT
blocks scattered between them are stray TLS socket read errors from
TLSWrap.onStreamRead
— keep‑alive sockets being torn down
after
the check completed. electron‑updater's HTTP layer logs those to stderr (that's why they have no
›
electron‑log prefix) but tolerates them. They never produce a rejected update promise, so they never reach your process‑level handlers. The app survives every time. The 05:58 event is the
only disconnect that coincided with the check actually firing
, and the network was
fully
down at that instant. So instead of a mid‑stream socket reset, Electron's network stack rejected the request at initiation: 05:58:02.824 › Error: Error: net::ERR_INTERNET_DISCONNECTED at SimpleURLLoaderWrapper... (Electron's net module, not Node's TLS) That error type
rejects the
checkForUpdatesAndNotify()
promise
, which the others did not. And that rejection is what kills you.
The actual crash mechanism
Two pieces of your bundled main combine into a footgun:
1.
The update check is called with no
.catch()
(
main-CBHvN0yQ.js:10916
):
const
r =
() =>
{ mainExports.autoUpdater.checkForUpdatesAndNotify(); }; The
autoUpdater.on("error", …)
listener logs
"Update error"
(line 10931) — that's the log line you see — but handling the
event
does
not
stop the returned
promise
from rejecting. So you get an
unhandledRejection
.
2.
Your global handler (
main-CBHvN0yQ.js:29946‑29967
): handleCryptoCrash =
(
r) => {
const
n = r.toString();
if
(n.includes(
"computeSecret"
) || n.includes(
"ERR_CRYPTO_ECDH..."
) || ...) {
// FCM key hot-recovery
return
; }
throw
r;
// <-- line 29964, the crash site in your log
}; process.on(
"uncaughtException"
, handleCryptoCrash); process.on(
"unhandledRejection"
, handleCryptoCrash); This handler exists to hot‑recover corrupted FCM push‑notification keys. For
anything else
it does
throw r
. Throwing from inside an
uncaughtException
/
unhandledRejection
handler is fatal — Node can't re‑catch it (that would loop), so it terminates the process. That's the
throw r
^ trace ending in
Node.js v22.21.1
. So the crash is essentially self‑inflicted: the disconnected‑at‑check‑time scenario is the one path that generates a non‑crypto unhandledRejection, and your handler rethrows it straight into process death.
Why "launched from terminal" mattered
Nothing about terminal launch causes the crash — the mechanism is identical under Finder/production. Launching from the terminal just let you
see
the stderr (
throw r
, the stack,
Node.js v22.21.1
). From Finder the same event would silently quit the app, which is exactly the "mystery crash on hotspot reconnect" you were chasing.
Fixes (in your source, not the bundle)
1.
Catch the update promise
— the
error
event already handles it, so the rejection is pure noise:
const
r =
() =>
{ autoUpdater.checkForUpdatesAndNotify().catch(
() =>
{}); }; 2.
Don't rethrow unrelated errors in
handleCryptoCrash
.
Re‑throwing in these handlers is what converts a survivable error into a hard exit. Log and swallow (or at least don't register it for
unhandledRejection
):
const
handleCryptoCrash =
(
r) => {
if
(isFcmCryptoError(r)) {
/* recover */
return
; }
console
.error(
"Unhandled:"
, r);
// log, don't throw r
}; Either fix alone stops this crash; #1 is the targeted fix, #2 closes the broader class of "any unhandled rejection kills Griply." I'd do both.
Please authenticate to join the conversation.
In Review
🐞 Bugs
2 months ago
Get notified by email when there are changes.
In Review
🐞 Bugs
2 months ago
Get notified by email when there are changes.