siyuan-note/siyuan · error

invalid template document attributes

Error message

invalid template document attributes

What it means

A fenced code block marked with the siyuan-template-doc-attrs-v1 marker was found but has no code body node. The document-attributes block is malformed: the fence info marker exists but the NodeCodeBlockCode child is missing, so the attribute payload cannot be extracted.

Source

Thrown at kernel/model/template_export_attrs.go:51

	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")
			}
			source := strings.TrimSpace(string(code.Tokens))
			attrs := parseTemplateDocumentAttributes(source)
			if len(attrs) == 0 {
				return errors.New("invalid template document attributes")
			}
			for _, attr := range attrs {
				if attr[0] == "id" || attr[0] == "updated" {
					continue
				}
				tree.Root.RemoveIALAttr(attr[0])
				tree.Root.KramdownIAL = append(tree.Root.KramdownIAL, attr)
			}
			if next != nil && next.Type == ast.NodeKramdownBlockIAL && parse.IAL2Map(parse.Tokens2IAL(next.Tokens))["type"] != "doc" {
				ial := next
				next = next.Next
				ial.Unlink()
			}

View on GitHub (pinned to 8641553a1f)

Solutions

  1. Add the attribute payload body inside the marker code block, or remove the marker code block entirely
  2. Use the app's save-as-template flow to regenerate a well-formed attributes block
  3. Do not hand-edit the siyuan-template-doc-attrs-v1 fence

Example fix

// before
```siyuan-template-doc-attrs-v1
```
// after (either fill the body or remove the block)
```siyuan-template-doc-attrs-v1
name: my-template
```
Defensive patterns

Strategy: validation

Validate before calling

// ensure the marker fence has a non-empty body before parsing
if strings.Contains(string(md), "siyuan-template-doc-attrs-v1") {
    var inBlock, hasBody bool
    for _, line := range strings.Split(string(md), "\n") {
        if strings.HasPrefix(strings.TrimSpace(line), "```siyuan-template-doc-attrs-v1") { inBlock = true; continue }
        if inBlock && strings.TrimSpace(line) == "```" { break }
        if inBlock && strings.TrimSpace(line) != "" { hasBody = true }
    }
    if !hasBody { return errors.New("doc-attrs fence has no body") }
}

Try / catch

if err := applyTemplateDocumentAttributes(tree); err != nil {
    return fmt.Errorf("fix or remove the siyuan-template-doc-attrs-v1 block: %w", err)
}

Prevention

When it happens

Trigger: applyTemplateDocumentAttributes encounters a code block whose info marker equals templateDocumentAttributeMarker but ChildByType(ast.NodeCodeBlockCode) returns nil — e.g. an empty or hand-edited fence block. Called via parseTemplateKTree from renderTemplateSource and renderTemplateDocTreeMarkdown.

Common situations: Hand-editing a template and leaving the marker fence without a body; a tool stripped the code content but kept the info marker; copy/paste lost the fenced body.

Understand the failure class

Background: Schema validation failed / invalid input schema: payload rejected because its shape doesn't match the expected schema — this error's family across 28 libraries.

Related errors


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