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 must be a JSON string. If it is a number, boolean, list, object, or null, the assertion to string fails. The title is used verbatim as a document path segment, so only strings are accepted.
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 8641553a1f)
Solutions
- Quote the title value: {"title": "2024"} instead of {"title": 2024}.
- In YAML templates, quote numeric-looking titles so the parser reads a string.
- Stringify values programmatically (e.g. fmt.Sprintf("%v", v) or JSON stringify) before building the definition.
- Pre-validate that typeof/Type-switch on each title is string before calling the API.
Example fix
// before
{"title": 2024}
// after
{"title": "2024"} Defensive patterns
Strategy: type-guard
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 }
if t, ok := m["title"]; ok {
if _, isStr := t.(string); !isStr {
return fmt.Errorf("title must be a string, got %T", t)
}
}
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 titleIsString(v any) bool {
m, ok := v.(map[string]any)
if !ok { return false }
t, ok := m["title"]
if !ok { return false }
_, isStr := t.(string)
return isStr
} Try / catch
nodes, err := parseTemplateDocTreeDefinition(def)
if err != nil {
if strings.Contains(err.Error(), "title must be a string") {
// stringify numeric/bool titles and retry
}
return err
} Prevention
- Quote numeric-looking titles in YAML/JSON templates.
- Stringify dynamic values before assigning them to title.
- Type-check titles in tooling before rendering.
When it happens
Trigger: Writing {"title": 42} or {"title": true}; passing a non-string variable into the definition builder; JSON templates where titles from numeric IDs were not stringified.
Common situations: Numeric document names from other systems not quoted; template engines interpolating numbers without conversion; YAML unquoted titles like title: 2024 parsed as integers.
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
- new item template field [%s] current time value is invalid
- new item template field [%s] value is invalid
- createDocTree definition must be a list
- createDocTree document must be a dictionary
- createDocTree document title must not be empty
AI-assisted analysis of siyuan-note/siyuan@8641553a1f (2026-09-11).
Data as JSON: /api/errors/e8613b532fd9293a.
Report an issue: GitHub.