Skip to content

fix: don't pass properties to createPage — it breaks Logseq's graph save and makes the app unquittable - #17

Merged
duydl merged 1 commit into
duydl:mainfrom
Lcstyle:fix/createpage-bean-breaks-graph-persist
Aug 11, 2026
Merged

fix: don't pass properties to createPage — it breaks Logseq's graph save and makes the app unquittable#17
duydl merged 1 commit into
duydl:mainfrom
Lcstyle:fix/createpage-bean-breaks-graph-persist

Conversation

@Lcstyle

@Lcstyle Lcstyle commented Aug 5, 2026

Copy link
Copy Markdown
Contributor

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_page 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 from then on every graph persist throws:

Error: Cannot write $cljs_bean$core$Bean$$
    at com.cognitect.transit.impl.writer/marshal
    ... frontend.db.utils/db->string ... frontend.db/persist!

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) createPage with 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:

Persist Page markdown
current createPage(title, props, …) fails — Bean in DB 263 B
this change ok 263 B, identical

Array values are joined with ", " and newlines collapsed, so a stray newline in a calibre field
can't break the property block.

I also checked the alternative I first suggested in #16createPage then upsertBlockProperty per
key. Don't use it: it produces a - bullet rather than a page-property pre-block, i.e. block
properties instead of page properties, which changes the file. This approach preserves the output.

Not changed

The addBlockInstead branch is left alone. insertBlock also runs bean/->clj over its opts
internally, but the block path renders properties into markdown as a:: b and re-parses them, so the
Bean 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):

Call Graph persists
createPage(name, {a:'b'}) — control no
insertBlock(uuid, content, { properties }) yes
insertBatchBlock(uuid, [{content, properties}]) yes
appendBlockInPage(page, content, { properties }) yes

So only the createPage branch needed changing. Sorry for flagging the insertBlock one as a
suspect in #16 before I'd tested it.

Testing

Built with npm run build and 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 is
source-only and the released bundle will come from your normal release flow.

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.
@duydl
duydl merged commit efdc516 into duydl:main Aug 11, 2026
1 check passed
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.

Adding a book makes Logseq unquittable and silently stops the graph cache saving (Logseq #8536; plugin-side workaround verified)

2 participants