You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
If frontend.db/persist! fails for any reason, Logseq becomes impossible to close for the rest of
the session, with no message to the user and nothing in logs/main.log beyond a single misleading
line.
I hit this via logseq/logseq#8536 (see my reproduction in logseq/logseq#8536 (comment)) (a cljs-beanBean in the DB, triggered by a plugin creating a page with
properties) and traced the quit path end to end. The trigger is incidental — the quit machinery has
three independent flaws that turn any persist failure into a hard hang.
My instance sat unquittable for 2 days 16 hours. Nothing was deadlocked or spinning: every thread
was sleeping, and the renderer answered executeJavaScript in 2 ms. The app was simply waiting
forever on a message that had already been sent — to a handler that doesn't exist.
1. :persistent-dbs-error has no handler
electron.listener/persist-dbs! wires the failure path:
:on-error (fn [] (ipc/ipc"persistent-dbs-error"))
In the shipped electron.js, persistent-dbs-saved appears twice; persistent-dbs-error appears
zero times. It falls through to the handle multimethod's :default, which only logs — and logs
the window object, not the channel name, so the log line doesn't even identify what failed:
That single line was the only trace of a 2.5-day outage.
2. The close handshake has no timeout
electron.window/close-handler:
(defnclose-handler [win close-watcher-f e]
(.preventDefault e) ;; window will not close
(.send web-contents "persistent-dbs") ;; ask renderer to save
(go (<! chan) ;; parks forever if the reply never comes
(.destroy win)))
An unbounded <! on a channel fed only by the success path. Suggested: alt! with a (timeout 10000) that destroys the window anyway and warns the user their DB cache wasn't saved.
The markdown files are already on disk, so this is safe — the .transit is only a cache.
3. The retry path is dead after the first attempt
The close listener registered in electron/core.cljs ends with (reset! *win* nil), and the
close-handler call is guarded by (when window_ ...) where window_ is @*win*. So:
1st close: preventDefault → close-handler → parks → *win* set to nil
2nd and every later close: preventDefault → window_ is nil → nothing happens at all
Verified on the stuck instance by replaying the close through the Electron main-process inspector:
close event fired : 1
defaultPrevented : true
6 s later : windowCount 1, destroyed false
renderer errors : [] <- persist-dbs! was never even invoked
new log lines : none
So the user clicks X, Quit, Ctrl+Q — and the application silently discards every one of them. On
macOS there's at least a transient "syncing internal status" toast; on Linux there is no feedback
whatsoever.
Impact
Application cannot be closed; force-kill is the only exit.
The DB cache silently stops being written. Mine last persisted Jul 25; I discovered this on Aug 2. Every launch in between was re-indexing more of the graph from markdown.
No user-visible error, and effectively no log trail.
What happened
If
frontend.db/persist!fails for any reason, Logseq becomes impossible to close for the rest ofthe session, with no message to the user and nothing in
logs/main.logbeyond a single misleadingline.
I hit this via logseq/logseq#8536 (see my reproduction in logseq/logseq#8536 (comment)) (a
cljs-beanBeanin the DB, triggered by a plugin creating a page withproperties) and traced the quit path end to end. The trigger is incidental — the quit machinery has
three independent flaws that turn any persist failure into a hard hang.
My instance sat unquittable for 2 days 16 hours. Nothing was deadlocked or spinning: every thread
was sleeping, and the renderer answered
executeJavaScriptin 2 ms. The app was simply waitingforever on a message that had already been sent — to a handler that doesn't exist.
1.
:persistent-dbs-errorhas no handlerelectron.listener/persist-dbs!wires the failure path:In the shipped
electron.js,persistent-dbs-savedappears twice;persistent-dbs-errorappearszero times. It falls through to the
handlemultimethod's:default, which only logs — and logsthe window object, not the channel name, so the log line doesn't even identify what failed:
That single line was the only trace of a 2.5-day outage.
2. The close handshake has no timeout
electron.window/close-handler:An unbounded
<!on a channel fed only by the success path. Suggested:alt!with a(timeout 10000)that destroys the window anyway and warns the user their DB cache wasn't saved.The markdown files are already on disk, so this is safe — the
.transitis only a cache.3. The retry path is dead after the first attempt
The
closelistener registered inelectron/core.cljsends with(reset! *win* nil), and theclose-handler call is guarded by
(when window_ ...)wherewindow_is@*win*. So:preventDefault→close-handler→ parks →*win*set tonilpreventDefault→window_isnil→ nothing happens at allVerified on the stuck instance by replaying the close through the Electron main-process inspector:
So the user clicks X, Quit, Ctrl+Q — and the application silently discards every one of them. On
macOS there's at least a transient "syncing internal status" toast; on Linux there is no feedback
whatsoever.
Impact
Aug 2. Every launch in between was re-indexing more of the graph from markdown.
comments on Unable to close Logseq, stuck at Syncing internal status logseq#8536 across 3.5 years, none of which found the trigger.
Suggested fix
:persistent-dbs-errorhandler that puts a distinguishable value on the same channel,so the go-block resumes and the window closes.
console.errorin devtools.<!inclose-handler— a slow or failed cache write must never make theapp unquittable.
:defaultipc handler log the channel name. Today it dumps the BrowserWindow, whichactively hides which message was unhandled.
(reset! *win* nil)before the close actually succeeds, so retrying is meaningful.Environment
Logseq 0.10.15 (Flathub
com.logseq.Logseq), Electron 38.4.0, Node 22.20.0,Fedora Linux 7.1.5, Wayland/COSMIC. File-based graph, 5228 pages.