siyuan-note/siyuan · error
parse tree failed
Error message
parse tree failed
What it means
After converting the payload to block DOM and parsing it into an AST (BlockDOM2Tree), parseBlockUpdateData verifies the tree exists and contains at least one content block (firstContentBlock). If the tree is nil, its root is nil, or there is no content block, the input produced an empty/unusable parse result and this error is returned.
Solutions
- Ensure the data payload contains at least one content block (a paragraph, heading, etc.)
- Check that the DOM/markdown string is not empty or whitespace-only before calling the API
- If clearing a block is intended, delete the block instead of updating it with empty content
Example fix
// before
await updateBlock({id, dataType: "dom", data: ""});
// after
await updateBlock({id, dataType: "dom", data: '<div data-node-id="..." data-type="NodeParagraph" class="p"><div class="p" contenteditable="true">new text</div></div>'}); Defensive patterns
Strategy: validation
Validate before calling
if (!payload.data || !payload.data.trim()) throw new Error("block update data must not be empty"); Try / catch
try {
await updateBlock(payload);
} catch (e) {
if (String(e.msg).includes("parse tree failed")) {
// payload produced no content block; supply non-empty content
}
} Prevention
- Never send empty or whitespace-only update payloads
- Delete blocks instead of updating them with empty content
- Sanity-check payloads after client-side transformations
When it happens
Trigger: Calling the block update API with data that converts to a tree with no content blocks — e.g. an empty string, whitespace-only content, or DOM containing only non-content elements. Also returned with dataType "dom" when the DOM string is blank or structurally empty.
Common situations: Scripts sending empty update payloads; race conditions where the block content was already cleared before the update call; clients constructing DOM strings with no renderable block node.
Understand the failure class
Background: "must not be empty", "cannot be empty" — required-field validation errors across open-source libraries — this error's family across 41 libraries.
Related errors
- block updates are empty
- Field [ ] must not be empty
- Field [ ] must not be empty
- Access to encrypted notebook data is not supported via this…
- AI editor action must not be empty
AI-assisted analysis of siyuan-note/siyuan@9f775e8a12 (2026-09-19).
Data as JSON: /api/errors/cc6b1b8aea645e06.
Report an issue: GitHub.
Appendix: source
Thrown at kernel/model/block_update.go:220
func parseBlockUpdateData(data, dataType string, luteEngine *lute.Lute) (ret string, tree *parse.Tree, err error) {
ret = data
switch dataType {
case "markdown":
ret, err = DataBlockDOM(data, luteEngine)
if err != nil {
err = fmt.Errorf("data block DOM failed: %w", err)
return
}
case "dom":
default:
err = fmt.Errorf("unsupported block data type [%s]", dataType)
return
}
tree = luteEngine.BlockDOM2Tree(ret)
if nil == tree || nil == tree.Root || nil == firstContentBlock(tree.Root) {
err = errors.New("parse tree failed")
}
return
}
func normalizeBlockUpdateTree(oldNode *ast.Node, tree *parse.Tree, luteEngine *lute.Lute) (ret *parse.Tree, updatedNode *ast.Node, err error) {
updatedNode, err = resolveBlockUpdateNode(oldNode, tree.Root)
if err != nil {
return nil, nil, err
}
updatedNode.Unlink()
root := &ast.Node{Type: ast.NodeDocument}
root.AppendChild(updatedNode)
ret = &parse.Tree{
Root: root,
Context: &parse.Context{ParseOption: luteEngine.ParseOptions},
}
returnView on GitHub (pinned to 9f775e8a12)