toeverything/AFFiNE · critical · BlockSuiteError
ErrorCode.NoRootModelError
ErrorCode.NoRootModelError
Error message
This doc is missing root block. Please initialize the default block structure before connecting the editor to DOM.
What it means
LitHost.connectedCallback (the <editor-host> root) requires store.root to exist before std.mount(); a doc with no root block has nothing to render, so BlockSuite fails fast with NoRootModelError. It tells you the document's block tree was not initialized (no root flavour like affine:page was ever added) before the editor was attached to the DOM.
Solutions
- Initialize the default block structure before connecting: use doc.load(init => init.block('affine:page', ...)) or add the page/root block, then mount the editor.
- For lazily loaded docs, wait for the doc content (workspace.doc loaded / doc.loaded await) before appending <editor-host>.
- Verify snapshot import actually created a root (check doc.root) and that the root flavour's schema is registered.
- Show a loading state until store.root is non-null instead of mounting early.
Example fix
// before
const doc = workspace.createDoc(docId);
document.body.append(editor); // NoRootModelError
// after
const doc = workspace.createDoc(docId);
doc.load(init => init.block('affine:page', {}, init.block('affine:surface', {})))
.then(() => document.body.append(editor)); Defensive patterns
Strategy: validation
Validate before calling
// Only mount the editor when the doc has a root:
if (doc.root) {
document.body.append(editor);
} else {
await doc.load(init => init.block('affine:page', {}));
document.body.append(editor);
} Type guard
function docHasRoot(doc: Store): boolean {
return doc.root != null;
} Prevention
- Initialize the default block structure (root page block) before connecting the editor host to DOM.
- Await doc.load()/doc.loaded for lazily fetched docs before mounting.
- Register the root flavour's schema; a missing schema can also leave root unresolved.
When it happens
Trigger: Creating a new empty doc (new Doc(...)) and appending the editor host before any root block exists; forgetting doc.load()/init with a default structure; importing a snapshot that failed or produced no root; referencing a doc id that has no data yet.
Common situations: Bootstrapping fresh workspaces without calling the standard init (e.g. doc.load(() => doc.addBlock('affine:page', {}, ...))); lazy-loading docs where the editor mounts before the (async) doc content arrives; snapshot middleware skipping the root node.
Related errors
- ErrorCode.MissingViewModelError
- ErrorCode.ValueNotExists
- Root block cannot have parent.
- Root block cannot have parent
- TransformerError
AI-assisted analysis of toeverything/AFFiNE@b4c8548c09 (2026-08-18).
Data as JSON: /api/errors/8ade845278c2bd83.
Report an issue: GitHub.
Appendix: source
Thrown at blocksuite/framework/std/src/view/element/lit-host.ts:131
}
get range(): RangeManager {
return this.std.range;
}
get selection(): StoreSelectionExtension {
return this.std.selection;
}
get view(): ViewStore {
return this.std.view;
}
override connectedCallback() {
super.connectedCallback();
if (!this.store.root) {
throw new BlockSuiteError(
ErrorCode.NoRootModelError,
'This doc is missing root block. Please initialize the default block structure before connecting the editor to DOM.'
);
}
this.std.mount();
this.tabIndex = 0;
}
override disconnectedCallback() {
super.disconnectedCallback();
this.std.unmount();
}
override async getUpdateComplete(): Promise<boolean> {
try {
const result = await super.getUpdateComplete();
const rootModel = this.store.root;View on GitHub (pinned to b4c8548c09)