{"record":{"id":"e8613b532fd9293a","repo":"siyuan-note/siyuan","slug":"createdoctree-document-title-must-be-a-string","errorCode":null,"errorMessage":"createDocTree document title must be a string","messagePattern":"createDocTree document title must be a string","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"kernel/model/template_doc_tree.go","lineNumber":153,"sourceCode":"\t\tdefinition, ok := value.(map[string]any)\n\t\tif !ok {\n\t\t\treturn nil, errors.New(\"createDocTree document must be a dictionary\")\n\t\t}\n\t\tfor key := range definition {\n\t\t\tswitch key {\n\t\t\tcase \"title\", \"template\", \"define\", \"children\":\n\t\t\tdefault:\n\t\t\t\treturn nil, fmt.Errorf(\"createDocTree document contains unknown field [%s]\", key)\n\t\t\t}\n\t\t}\n\n\t\ttitleValue, ok := definition[\"title\"]\n\t\tif !ok {\n\t\t\treturn nil, errors.New(\"createDocTree document title is required\")\n\t\t}\n\t\ttitle, ok := titleValue.(string)\n\t\tif !ok {\n\t\t\treturn nil, errors.New(\"createDocTree document title must be a string\")\n\t\t}\n\t\ttitle = normalizeDocTitle(title)\n\t\tif \"\" == title {\n\t\t\treturn nil, errors.New(\"createDocTree document title must not be empty\")\n\t\t}\n\t\tif 512 < utf8.RuneCountInString(title) {\n\t\t\treturn nil, fmt.Errorf(\"createDocTree document title exceeds %d characters\", 512)\n\t\t}\n\n\t\ttemplateName, err := templateDocTreeStringField(definition, \"template\")\n\t\tif nil != err {\n\t\t\treturn nil, err\n\t\t}\n\t\tdefineName, err := templateDocTreeStringField(definition, \"define\")\n\t\tif nil != err {\n\t\t\treturn nil, err\n\t\t}\n\t\tif \"\" != templateName && \"\" != defineName {","sourceCodeStart":135,"sourceCodeEnd":171,"githubUrl":"https://github.com/siyuan-note/siyuan/blob/8641553a1f07374001902d3ce773285db1292b2d/kernel/model/template_doc_tree.go#L135-L171","documentation":"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.","triggerScenarios":"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.","commonSituations":"Numeric document names from other systems not quoted; template engines interpolating numbers without conversion; YAML unquoted titles like title: 2024 parsed as integers.","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."],"exampleFix":"// before\n{\"title\": 2024}\n// after\n{\"title\": \"2024\"}","handlingStrategy":"type-guard","validationCode":"var walk func(nodes []any) error\nwalk = func(nodes []any) error {\n    for _, v := range nodes {\n        m, ok := v.(map[string]any)\n        if !ok { continue }\n        if t, ok := m[\"title\"]; ok {\n            if _, isStr := t.(string); !isStr {\n                return fmt.Errorf(\"title must be a string, got %T\", t)\n            }\n        }\n        if c, ok := m[\"children\"]; ok {\n            if cl, ok := c.([]any); ok {\n                if err := walk(cl); err != nil { return err }\n            }\n        }\n    }\n    return nil\n}","typeGuard":"func titleIsString(v any) bool {\n    m, ok := v.(map[string]any)\n    if !ok { return false }\n    t, ok := m[\"title\"]\n    if !ok { return false }\n    _, isStr := t.(string)\n    return isStr\n}","tryCatchPattern":"nodes, err := parseTemplateDocTreeDefinition(def)\nif err != nil {\n    if strings.Contains(err.Error(), \"title must be a string\") {\n        // stringify numeric/bool titles and retry\n    }\n    return err\n}","preventionTips":["Quote numeric-looking titles in YAML/JSON templates.","Stringify dynamic values before assigning them to title.","Type-check titles in tooling before rendering."],"tags":["template","type-mismatch","title"],"backgroundTag":"type-mismatch","analyzedSha":"8641553a1f07374001902d3ce773285db1292b2d","analyzedAt":"2026-09-11T16:08:28.414Z","contentChangedAt":"2026-09-11T16:08:28.414Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}