fix(editor): heal empty block ids that crash the editor#679
Merged
Conversation
Notes with 2+ consecutive blank lines that re-hydrated from markdown (seed-from-markdown, external .md edit, or sync) were persisted with an empty-string block id. BlockNote's headless serializer regenerates a MISSING id but writes an explicit '' as-is; on mount the renderer's block resolver throws "Block doesn't have id" and the editor error boundary shows "Editor Error". Refresh can't help because the empty id lives in the persisted CRDT. - createEmptyParagraph no longer seeds id: '' (uses randomUUID) - blocksToYFragment defensively stamps a uuid on any falsy block id - repairEmptyBlockIds heals already-corrupted notes on open (crdt-provider) - regression tests for the converter output + repair helper
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
h4yfans
added a commit
that referenced
this pull request
Jul 3, 2026
Desktop tests (Unit coverage step) had accumulated pre-existing failures masked behind the CLI-test red (which skipped the desktop step): - crdt-provider: add repairEmptyBlockIds to blocknote-converter mock (#679) - date rendering (date-grouping, format-task-due, tab-preview-card, missing-small-components, component-major-surfaces): expect DD.MM.YYYY default from configurable date format (#671) - general-section.i18n: tabCloseButton is selects[3] after the added dateFormat select (#671) - settings-sections: editor/journal switch indices shift +1 after the calendar notes-on-calendar switch (#667) - missing-small-components: add getI18n to react-i18next mock (fixes an unhandled rejection that failed the whole run) E2E auth-state-machine: recovery-phrase words are semantic <li> after the React Doctor a11y pass (#639) dropped explicit role=listitem; query by 'li'.
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.
Problem
A few notes showed "Editor Error — The editor encountered an error", technical details starting with
Block doesn't have id at kt…. Refresh didn't help.Root cause: those notes had a block persisted with an empty-string
id(""). BlockNote'sktresolver runsif (!id) throw "Block doesn't have id", and!"" === true, so an empty id reads as missing and the editor crashes on mount. The error boundary then shows "Editor Error". The note text itself is fine — only the block's id attribute is empty.Why it happened
The markdown→CRDT converter mints one gap paragraph per extra blank line, and
createEmptyParagraph()hard-codedid: ''. The headless serializer (blocksToYXmlFragment) regenerates a missing id into a real UUID, but writes an explicit empty string as-is. So any note with 2+ consecutive blank lines that re-hydrated from markdown —seedFromMarkdown, an external.mdedit, or sync — persisted an empty-id block. Notes edited purely in the live editor keep real UUIDs, which is why only some notes broke, and why reload never fixed them (the empty id is in the persisted CRDT).Fix
createEmptyParagraph()no longer seedsid: ''(usesrandomUUID()).blocksToYFragmentdefensively stamps a UUID on any block whose id is falsy before serializing — closes the empty-string footgun at the write choke point.repairEmptyBlockIds()walks the CRDT fragment on note open and re-ids any empty/missing block container, so already-corrupted notes self-heal and re-persist (wired intocrdt-providerload path).Tests
blocknote-converter.test.ts— new "block id integrity" suite:blocksToYFragmentregenerates a falsy idrepairEmptyBlockIdsstamps missing ids and leaves valid ones untouchedReproduce
Externally edit a vault note's
.mdto have a double blank line between two lines of text, then reopen the note — before this change it throws "Editor Error".