fix: don't pass properties to createPage — it breaks Logseq's graph save and makes the app unquittable - #17
Merged
duydl merged 1 commit intoAug 11, 2026
Conversation
Logseq's create_page API converts the properties argument with cljs-bean's
->clj, which yields a lazy Bean view rather than a real map, and stores it as
the page entity's :block/properties. datascript-transit has no write handler
for a Bean, so once one is in the DB every graph persist throws
Error: Cannot write $cljs_bean$core$Bean$$
... frontend.db.utils/db->string ... frontend.db/persist!
and because the main process has no handler for the resulting
"persistent-dbs-error" reply, Logseq can no longer be closed at all for the rest
of the session - no dialog, no log line, X and Quit silently do nothing.
That is logseq/logseq#8536, open upstream since 2023. Until it ships, adding a
book with this plugin reliably triggers it.
Writing the properties as the first block's content instead routes them through
Logseq's markdown property parser, which produces a genuine map. Verified the
resulting page file is byte-identical to what the old call produced (263 bytes
either way) while the graph now persists cleanly.
Array values are joined and newlines collapsed so a stray newline in a calibre
field cannot break the property block.
The addBlockInstead branch is left alone: insertBlock renders properties through
markdown already, so it was never affected.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Fixes #16.
What happens today
Adding a book makes Logseq's graph cache stop saving, and the app can no longer be closed for the
rest of the session — X, Quit and Ctrl/Cmd+Q all silently do nothing, with no dialog and no log line.
The underlying defect is in Logseq, not this plugin:
logseq.api/create_pageconverts thepropertiesargument withcljs-bean's->clj, which yields a lazyBeanview rather than a realmap, and stores it as the page entity's
:block/properties.datascript-transithas no writehandler for a
Bean, so from then on every graph persist throws:and Logseq's close handler waits forever for a save confirmation that never arrives.
That's logseq/logseq#8536, open upstream since 2023.
I've filed fixes for it at logseq/og#42 and
logseq/og#43, but until those ship (and reach everyone's
install)
createPagewith properties is unusable, and this plugin calls it on every book added.On my machine the graph cache silently stopped being written for eight days before I noticed,
and the app sat unquittable for 2 days 16 hours.
The change
Create the page without properties, then write the properties as the first block's content. That
goes through Logseq's markdown property parser, which produces a genuine map.
I verified the generated page file is byte-identical to what the current code produces — same 263
bytes, same page-property pre-block — while the graph persists cleanly:
createPage(title, props, …)Array values are joined with
", "and newlines collapsed, so a stray newline in a calibre fieldcan't break the property block.
I also checked the alternative I first suggested in #16 —
createPagethenupsertBlockPropertyperkey. Don't use it: it produces a
-bullet rather than a page-property pre-block, i.e. blockproperties instead of page properties, which changes the file. This approach preserves the output.
Not changed
The
addBlockInsteadbranch is left alone.insertBlockalso runsbean/->cljover its optsinternally, but the block path renders properties into markdown as
a:: band re-parses them, so theBean is transient and never reaches the DB. I tested it explicitly (with
createPage(name, {a:'b'})as a positive control to make sure the test could detect the bug at all):
createPage(name, {a:'b'})— controlinsertBlock(uuid, content, { properties })insertBatchBlock(uuid, [{content, properties}])appendBlockInPage(page, content, { properties })So only the
createPagebranch needed changing. Sorry for flagging theinsertBlockone as asuspect in #16 before I'd tested it.
Testing
Built with
npm run buildand installed into a real Logseq 0.10.15 (Flathub) with a 5228-page graph;the plugin loads and the page output is unchanged. Note
dist/is gitignored here, so this diff issource-only and the released bundle will come from your normal release flow.