{"record":{"id":"67a849237dfa89cf","repo":"siyuan-note/siyuan","slug":"parse-template-tree-failed","errorCode":null,"errorMessage":"parse template tree failed","messagePattern":"parse template tree failed","errorType":"error_code","errorClass":null,"httpStatus":null,"severity":"error","filePath":"kernel/model/template_export_attrs.go","lineNumber":34,"sourceCode":"\npackage model\n\nimport (\n\t\"bytes\"\n\t\"errors\"\n\t\"strings\"\n\n\t\"github.com/88250/lute/ast\"\n\t\"github.com/88250/lute/parse\"\n)\n\nconst templateDocumentAttributeMarker = \"siyuan-template-doc-attrs-v1\"\n\nfunc parseTemplateKTree(markdown []byte) (*parse.Tree, error) {\n\tengine := NewLute()\n\ttree := parse.Parse(\"\", markdown, engine.ParseOptions)\n\tif tree == nil {\n\t\treturn nil, errors.New(\"parse template tree failed\")\n\t}\n\tnormalizeTree(tree)\n\tif err := applyTemplateDocumentAttributes(tree); err != nil {\n\t\treturn nil, err\n\t}\n\treturn tree, nil\n}\n\n// 独立文档属性保留在原位置求值，渲染完成后再合并到根节点。\nfunc applyTemplateDocumentAttributes(tree *parse.Tree) error {\n\tfor node := tree.Root.FirstChild; node != nil; {\n\t\tnext := node.Next\n\t\tinfo := node.ChildByType(ast.NodeCodeBlockFenceInfoMarker)\n\t\tif node.Type == ast.NodeCodeBlock && info != nil && string(info.CodeBlockInfo) == templateDocumentAttributeMarker {\n\t\t\tcode := node.ChildByType(ast.NodeCodeBlockCode)\n\t\t\tif code == nil {\n\t\t\t\treturn errors.New(\"invalid template document attributes\")\n\t\t\t}","sourceCodeStart":16,"sourceCodeEnd":52,"githubUrl":"https://github.com/siyuan-note/siyuan/blob/8641553a1f07374001902d3ce773285db1292b2d/kernel/model/template_export_attrs.go#L16-L52","documentation":"parseTemplateKTree could not produce a valid parse tree from the template markdown. The Lute parser (parse.Parse) returned nil, meaning the input could not be parsed into a tree, so a descriptive error is returned instead of a nil-tree panic downstream.","triggerScenarios":"parse.Parse(\"\", markdown, engine.ParseOptions) returns nil inside parseTemplateKTree, called from renderTemplateSource, renderTemplateDocTreeMarkdown, or TestTemplateDocumentAttributeFormats when given malformed or empty/unparseable template markdown.","commonSituations":"Corrupted or truncated .md template files; a template containing bytes the parser cannot handle; passing nil/empty markdown due to an earlier failed file read whose error was ignored.","solutions":["Check the template markdown file exists, is non-empty, and is valid UTF-8 before calling","Verify the caller checked the read error before passing markdown bytes","Re-save or recreate the corrupted template file"],"exampleFix":"// before\nmarkdown, _ := os.ReadFile(p) // error ignored -> nil tree\ntree, err := parseTemplateKTree(markdown)\n// after\nmarkdown, err := os.ReadFile(p)\nif err != nil { return err }\ntree, err := parseTemplateKTree(markdown)\n","handlingStrategy":"try-catch","validationCode":"if len(markdown) == 0 || !utf8.Valid(markdown) { return errors.New(\"empty or non-UTF8 template markdown\") }","typeGuard":"func validTree(t *parse.Tree) bool { return t != nil && t.Root != nil }","tryCatchPattern":"tree, err := parseTemplateKTree(markdown)\nif err != nil {\n    log.Errorf(\"template parse failed: %v\", err)\n    return fmt.Errorf(\"template is unparseable, re-save it: %w\", err)\n}","preventionTips":["Always check the file-read error before passing markdown bytes","Validate templates are non-empty valid UTF-8 markdown","Re-save corrupted templates instead of hand-patching bytes"],"tags":["template","parser","markdown"],"backgroundTag":"json-parse-error","analyzedSha":"8641553a1f07374001902d3ce773285db1292b2d","analyzedAt":"2026-09-11T16:08:28.414Z","contentChangedAt":"2026-09-11T16:08:28.414Z","schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}