siyuan-note/siyuan · error

createDocTree document template and define are mutually excl

Error message

createDocTree document template and define are mutually exclusive

What it means

A createDocTree document may specify how its content is produced either by referencing an existing template file (template) or by an inline define block, but not both. Supplying both non-empty template and define fields is ambiguous and rejected by parseNodes.

Source

Thrown at kernel/model/template_doc_tree.go:172

		}
		title = normalizeDocTitle(title)
		if "" == title {
			return nil, errors.New("createDocTree document title must not be empty")
		}
		if 512 < utf8.RuneCountInString(title) {
			return nil, fmt.Errorf("createDocTree document title exceeds %d characters", 512)
		}

		templateName, err := templateDocTreeStringField(definition, "template")
		if nil != err {
			return nil, err
		}
		defineName, err := templateDocTreeStringField(definition, "define")
		if nil != err {
			return nil, err
		}
		if "" != templateName && "" != defineName {
			return nil, errors.New("createDocTree document template and define are mutually exclusive")
		}

		state.count++
		if maxTemplateDocTreeDocs < state.count {
			return nil, fmt.Errorf("createDocTree exceeds the maximum document count of %d", maxTemplateDocTreeDocs)
		}
		id := ast.NewNodeID()
		node := &TemplateDocTreeNode{
			ID:       id,
			RootID:   id,
			Title:    title,
			Depth:    depth,
			Template: templateName,
			Define:   defineName,
		}
		if childrenValue, exists := definition["children"]; exists {
			children, parseErr := state.parseNodes(childrenValue, depth+1)
			if nil != parseErr {

View on GitHub (pinned to 8641553a1f)

Solutions

  1. Keep only one content source: delete the template field to use the inline define, or delete define to use the template file.
  2. If both behaviors are wanted, nest documents: one child with template and a sibling child with define.
  3. In generated definitions, emit template XOR define based on which source is available.
  4. Pre-validate: reject any node where both fields are non-empty strings before rendering.

Example fix

// before
{"title": "Daily", "template": "daily.md", "define": "content here"}
// after (use define)
{"title": "Daily", "define": "content here"}
Defensive patterns

Strategy: validation

Validate before calling

var walk func(nodes []any) error
walk = func(nodes []any) error {
    for _, v := range nodes {
        m, ok := v.(map[string]any)
        if !ok { continue }
        tpl, _ := m["template"].(string)
        def, _ := m["define"].(string)
        if tpl != "" && def != "" {
            return errors.New("template and define are mutually exclusive on one document")
        }
        if c, ok := m["children"]; ok {
            if cl, ok := c.([]any); ok {
                if err := walk(cl); err != nil { return err }
            }
        }
    }
    return nil
}

Type guard

func hasOneContentSource(v any) bool {
    m, ok := v.(map[string]any)
    if !ok { return false }
    tpl, _ := m["template"].(string)
    def, _ := m["define"].(string)
    return tpl == "" || def == ""
}

Try / catch

nodes, err := parseTemplateDocTreeDefinition(def)
if err != nil {
    if strings.Contains(err.Error(), "mutually exclusive") {
        // drop template or define on the offending node and retry
    }
    return err
}

Prevention

When it happens

Trigger: A document object like {"title": "X", "template": "note.md", "define": "..."}; merging two definition styles when refactoring; copy-pasting fields from two different example documents into one.

Common situations: Authors unsure of the two mechanisms adding both to be safe; generated definitions that always emit both keys with defaults; editing a template-based entry to inline content while forgetting to delete the template field.

Related errors


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