{"record":{"id":"cc6b1b8aea645e06","repo":"siyuan-note/siyuan","slug":"parse-tree-failed","errorCode":null,"errorMessage":"parse tree failed","messagePattern":"parse tree failed","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"kernel/model/block_update.go","lineNumber":220,"sourceCode":"\nfunc parseBlockUpdateData(data, dataType string, luteEngine *lute.Lute) (ret string, tree *parse.Tree, err error) {\n\tret = data\n\tswitch dataType {\n\tcase \"markdown\":\n\t\tret, err = DataBlockDOM(data, luteEngine)\n\t\tif err != nil {\n\t\t\terr = fmt.Errorf(\"data block DOM failed: %w\", err)\n\t\t\treturn\n\t\t}\n\tcase \"dom\":\n\tdefault:\n\t\terr = fmt.Errorf(\"unsupported block data type [%s]\", dataType)\n\t\treturn\n\t}\n\n\ttree = luteEngine.BlockDOM2Tree(ret)\n\tif nil == tree || nil == tree.Root || nil == firstContentBlock(tree.Root) {\n\t\terr = errors.New(\"parse tree failed\")\n\t}\n\treturn\n}\n\nfunc normalizeBlockUpdateTree(oldNode *ast.Node, tree *parse.Tree, luteEngine *lute.Lute) (ret *parse.Tree, updatedNode *ast.Node, err error) {\n\tupdatedNode, err = resolveBlockUpdateNode(oldNode, tree.Root)\n\tif err != nil {\n\t\treturn nil, nil, err\n\t}\n\n\tupdatedNode.Unlink()\n\troot := &ast.Node{Type: ast.NodeDocument}\n\troot.AppendChild(updatedNode)\n\tret = &parse.Tree{\n\t\tRoot:    root,\n\t\tContext: &parse.Context{ParseOption: luteEngine.ParseOptions},\n\t}\n\treturn","sourceCodeStart":202,"sourceCodeEnd":238,"githubUrl":"https://github.com/siyuan-note/siyuan/blob/251596fc0de2f9528c00c224252fd073a99973f4/kernel/model/block_update.go#L202-L238","documentation":"Returned by parseBlockUpdateData after BlockDOM2Tree(ret). If the parsed tree is nil, its Root is nil, or firstContentBlock(tree.Root) is nil, the input DOM has no usable content block. The DOM parsed to completion but produced an empty or root-only tree.","triggerScenarios":"DOM with only whitespace/zero-width characters; DOM consisting solely of container elements with no leaf content; DOM whose first content block was stripped by Lute sanitization.","commonSituations":"Pasting an empty paragraph; DOM that is all list containers with no list items; sanitization stripping all content leaving an empty shell.","solutions":["Inspect the DOM string - confirm it contains at least one addressable content block.","Strip zero-width characters and pure-whitespace nodes before submission.","Regenerate the DOM from a known-good source (re-render the block in the editor and copy its DOM)."],"exampleFix":null,"handlingStrategy":"validation","validationCode":"// trim zero-width / whitespace-only content before submission\ncleaned := strings.ReplaceAll(input.Data, \"\\u200b\", \"\")\nif strings.TrimSpace(stripTags(cleaned)) == \"\" {\n    return errors.New(\"empty content\")\n}","typeGuard":null,"tryCatchPattern":"ops, roots, err := buildBlockUpdateOperations(inputs, resolver, loader)\nif err != nil && strings.Contains(err.Error(), \"parse tree failed\") {\n    // regenerate DOM in the editor and retry\n}","preventionTips":["Strip zero-width and whitespace-only nodes from DOM before submit.","Confirm the DOM has at least one addressable content block.","Re-copy DOM fresh from the editor rather than caching."],"tags":["block-update","dom","lute","parse"],"backgroundTag":null,"analyzedSha":"251596fc0de2f9528c00c224252fd073a99973f4","analyzedAt":"2026-08-12T21:18:37.123Z","schemaVersion":2},"datasetVersion":"2026-08-12T23:17:12.415Z"}