siyuan-note/siyuan · error

createDocTree document %s must be a string

Error message

createDocTree document %s must be a string

What it means

templateDocTreeStringField validates the optional "template" or "define" field of a createDocTree document entry. If the key exists but its value is not a JSON string (e.g. a number, boolean, object, or array), parsing fails with "createDocTree document <key> must be a string". The parser is strict because both fields are later resolved to template file names.

Source

Thrown at kernel/model/template_doc_tree.go:207

			children, parseErr := state.parseNodes(childrenValue, depth+1)
			if nil != parseErr {
				return nil, parseErr
			}
			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)

View on GitHub (pinned to 8641553a1f)

Solutions

  1. Quote the value: change "template": 123 to "template": "123".
  2. Remove the field entirely if no child template/define is needed (absent keys are allowed).
  3. If generated by code, coerce the value to a string before building the definition (e.g. str(value)).

Example fix

// before
{"title":"Child","template":42}
// after
{"title":"Child","template":"child-template"}
Defensive patterns

Strategy: validation

Validate before calling

for (const doc of definition) {
  for (const key of ["template", "define"]) {
    if (key in doc && typeof doc[key] !== "string") throw new Error(`${key} must be a string`);
  }
}

Type guard

const isNonEmptyString = (v) => typeof v === "string" && v.trim().length > 0;

Try / catch

try {
  render(def);
} catch (e) {
  if (/must be a string/.test(String(e))) {
    // fix the offending field type in the definition
  }
}

Prevention

When it happens

Trigger: A createDocTree document entry like {"title":"x","template":123}, {"title":"x","define":true}, or {"template":{...}} passed to the collector's create() or rendered via parseTemplateDocTreeDefinition.

Common situations: Hand-writing template syntax with an unquoted value, JSON produced by a script using non-string types, or copying a doc entry where the field was set programmatically to a number/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@8641553a1f (2026-09-11). Data as JSON: /api/errors/efdb81e505eab0b4. Report an issue: GitHub.