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

  1. Ensure the data payload contains at least one content block (a paragraph, heading, etc.)
  2. Check that the DOM/markdown string is not empty or whitespace-only before calling the API
  3. 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

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


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},
	}
	return

View on GitHub (pinned to 9f775e8a12)