siyuan-note/siyuan · error

createDocTree document title must be a string

Error message

createDocTree document title must be a string

What it means

The title field of a createDocTree document must be a JSON string; parseNodes performs a Go type assertion and rejects numbers, booleans, null, objects, or lists. This guarantees the title can be used directly as a document path segment.

Solutions

  1. Quote the title so it is a JSON string: {"title": "42"}.
  2. In the generator, convert the title value to a string before serialization.
  3. Validate the definition with a type check before invoking the template action.

Example fix

// before
{"title": 20260918}
// after
{"title": "20260918"}
Defensive patterns

Strategy: type-guard

Validate before calling

docs.forEach(d => { if (typeof d.title !== "string") d.title = String(d.title); });

Type guard

const hasStringTitle = (d) => typeof d.title === 'string';

Try / catch

try {
  createDocTree(def);
} catch (e) {
  if (String(e).includes("title must be a string")) {
    def = def.map(d => ({...d, title: String(d.title)}));
  }
}

Prevention

When it happens

Trigger: Passing a non-string title, e.g. {"title": 42}, {"title": true}, {"title": null}, or {"title": ["Doc"]} in a createDocTree definition. Raised from parseTemplateDocTreeDefinition during editor template insertion.

Common situations: Generating the definition from a script where dates or counters become numbers; templating engines rendering {{date}} as a number; JSON where an empty placeholder was serialized as null.

Understand the failure class

Background: Type mismatch errors: IllegalArgumentException, TypeError and type guards across 150 open-source libraries — this error's family across 150 libraries.

Related errors


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

Appendix: source

Thrown at kernel/model/template_doc_tree.go:153

		definition, ok := value.(map[string]any)
		if !ok {
			return nil, errors.New("createDocTree document must be a dictionary")
		}
		for key := range definition {
			switch key {
			case "title", "template", "define", "children":
			default:
				return nil, fmt.Errorf("createDocTree document contains unknown field [%s]", key)
			}
		}

		titleValue, ok := definition["title"]
		if !ok {
			return nil, errors.New("createDocTree document title is required")
		}
		title, ok := titleValue.(string)
		if !ok {
			return nil, errors.New("createDocTree document title must be a string")
		}
		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 {

View on GitHub (pinned to 9f775e8a12)