siyuan-note/siyuan · error

parse template tree failed

Error message

parse template tree failed

What it means

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.

Source

Thrown at kernel/model/template_export_attrs.go:34

package model

import (
	"bytes"
	"errors"
	"strings"

	"github.com/88250/lute/ast"
	"github.com/88250/lute/parse"
)

const templateDocumentAttributeMarker = "siyuan-template-doc-attrs-v1"

func parseTemplateKTree(markdown []byte) (*parse.Tree, error) {
	engine := NewLute()
	tree := parse.Parse("", markdown, engine.ParseOptions)
	if tree == nil {
		return nil, errors.New("parse template tree failed")
	}
	normalizeTree(tree)
	if err := applyTemplateDocumentAttributes(tree); err != nil {
		return nil, err
	}
	return tree, nil
}

// 独立文档属性保留在原位置求值,渲染完成后再合并到根节点。
func applyTemplateDocumentAttributes(tree *parse.Tree) error {
	for node := tree.Root.FirstChild; node != nil; {
		next := node.Next
		info := node.ChildByType(ast.NodeCodeBlockFenceInfoMarker)
		if node.Type == ast.NodeCodeBlock && info != nil && string(info.CodeBlockInfo) == templateDocumentAttributeMarker {
			code := node.ChildByType(ast.NodeCodeBlockCode)
			if code == nil {
				return errors.New("invalid template document attributes")
			}

View on GitHub (pinned to 8641553a1f)

Solutions

  1. Check the template markdown file exists, is non-empty, and is valid UTF-8 before calling
  2. Verify the caller checked the read error before passing markdown bytes
  3. Re-save or recreate the corrupted template file

Example fix

// before
markdown, _ := os.ReadFile(p) // error ignored -> nil tree
tree, err := parseTemplateKTree(markdown)
// after
markdown, err := os.ReadFile(p)
if err != nil { return err }
tree, err := parseTemplateKTree(markdown)
Defensive patterns

Strategy: try-catch

Validate before calling

if len(markdown) == 0 || !utf8.Valid(markdown) { return errors.New("empty or non-UTF8 template markdown") }

Type guard

func validTree(t *parse.Tree) bool { return t != nil && t.Root != nil }

Try / catch

tree, err := parseTemplateKTree(markdown)
if err != nil {
    log.Errorf("template parse failed: %v", err)
    return fmt.Errorf("template is unparseable, re-save it: %w", err)
}

Prevention

When it happens

Trigger: parse.Parse("", markdown, engine.ParseOptions) returns nil inside parseTemplateKTree, called from renderTemplateSource, renderTemplateDocTreeMarkdown, or TestTemplateDocumentAttributeFormats when given malformed or empty/unparseable template markdown.

Common situations: 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.

Understand the failure class

Background: JSON parse error: "Unexpected token" / "not valid JSON" / "failed to parse" — what JSON parsers are really complaining about — this error's family across 45 libraries.

Related errors


AI-assisted analysis of siyuan-note/siyuan@8641553a1f (2026-09-11). Data as JSON: /api/errors/67a849237dfa89cf. Report an issue: GitHub.