siyuan-note/siyuan · error

createDocTree document

Error message

createDocTree document %s must not be empty

What it means

If the template or define field of a createDocTree document is present but trims to an empty string, templateDocTreeStringField rejects it. An explicitly present-but-blank content reference is treated as a mistake rather than ignored, so users are not silently given a document with no content source.

Solutions

  1. Remove the template/define key entirely when no content source is intended.
  2. Fill in an actual template file name or define id.
  3. In generator code, omit empty fields instead of serializing empty strings.
  4. Trim and filter empty values before building the definition object.

Example fix

// before
{"title": "Doc", "template": ""}
// after
{"title": "Doc"}
Defensive patterns

Strategy: validation

Validate before calling

function cleanDoc(d) {
  for (const k of ['template', 'define']) {
    if (typeof d[k] === 'string' && d[k].trim() === '') delete d[k];
  }
  return d;
}
docs = docs.map(cleanDoc);

Prevention

When it happens

Trigger: Passing "template": "" or "define": " " (whitespace only) in a document object. The key exists, so the missing-field path is skipped, but the trimmed value is empty. Raised from parseNodes via parseTemplateDocTreeDefinition.

Common situations: Template variables that resolve to empty strings; generator code initializing fields to "" instead of omitting them; user-cleared input in a template builder UI serialized as an empty key.

Understand the failure class

Background: "must not be empty", "cannot be empty" — required-field validation errors across open-source libraries — this error's family across 41 libraries.

Related errors


AI-assisted analysis of siyuan-note/siyuan@9f775e8a12 (2026-09-19). Data as JSON: /api/errors/23a9f7bf16bcb788. Report an issue: GitHub.

Appendix: source

Thrown at kernel/model/template_doc_tree.go:211

			node.Children = children
		}
		nodes = append(nodes, node)
	}
	return nodes, nil
}

func templateDocTreeStringField(definition map[string]any, key string) (string, error) {
	value, exists := definition[key]
	if !exists {
		return "", nil
	}
	ret, ok := value.(string)
	if !ok {
		return "", fmt.Errorf("createDocTree document %s must be a string", key)
	}
	ret = strings.TrimSpace(ret)
	if "" == ret {
		return "", fmt.Errorf("createDocTree document %s must not be empty", key)
	}
	return ret, nil
}

func (collector *templateDocTreeCollector) create(def any) (string, error) {
	if !collector.enabled || !collector.allowCreation {
		return "", errors.New("createDocTree is only available when manually inserting a template in the editor")
	}
	nodes, err := parseTemplateDocTreeDefinition(def)
	if nil != err {
		return "", err
	}
	if maxTemplateDocTreeDocs < len(flattenTemplateDocTreeNodes0(collector.nodes))+len(flattenTemplateDocTreeNodes0(nodes)) {
		return "", fmt.Errorf("createDocTree exceeds the maximum document count of %d", maxTemplateDocTreeDocs)
	}
	collector.bindNodes(nodes, collector.rootID, collector.rootPath, collector.rootHPath)
	collector.nodes = append(collector.nodes, nodes...)
	return "", nil

View on GitHub (pinned to 9f775e8a12)