{"record":{"id":"352a8c51cfe08923","repo":"siyuan-note/siyuan","slug":"createdoctree-document-list-must-not-be-empty","errorCode":null,"errorMessage":"createDocTree document list must not be empty","messagePattern":"createDocTree document list must not be empty","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"kernel/model/template_doc_tree.go","lineNumber":130,"sourceCode":"\t\treturn nil, errors.New(\"createDocTree requires at least one document\")\n\t}\n\treturn nodes, nil\n}\n\ntype templateDocTreeParseState struct {\n\tcount int\n}\n\nfunc (state *templateDocTreeParseState) parseNodes(value any, depth int) ([]*TemplateDocTreeNode, error) {\n\tif maxTemplateDocTreeDepth < depth {\n\t\treturn nil, fmt.Errorf(\"createDocTree exceeds the maximum depth of %d\", maxTemplateDocTreeDepth)\n\t}\n\tvalues, ok := value.([]any)\n\tif !ok {\n\t\treturn nil, errors.New(\"createDocTree definition must be a list\")\n\t}\n\tif 0 == len(values) {\n\t\treturn nil, errors.New(\"createDocTree document list must not be empty\")\n\t}\n\n\tnodes := make([]*TemplateDocTreeNode, 0, len(values))\n\tfor _, value := range values {\n\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 {","sourceCodeStart":112,"sourceCodeEnd":148,"githubUrl":"https://github.com/siyuan-note/siyuan/blob/8641553a1f07374001902d3ce773285db1292b2d/kernel/model/template_doc_tree.go#L112-L148","documentation":"An empty list was supplied where parseNodes expected at least one document definition. Either the top-level createDocTree array is empty or a children array is empty ([]). Because an empty list can never produce a document, the parser rejects it immediately.","triggerScenarios":"Calling createDocTree with definition []; providing children: [] on a document node; a filter/template step that strips all entries from the list before rendering.","commonSituations":"Generated templates where the data source returned no rows; a template author leaving children: [] as a placeholder; variables interpolating to empty arrays at render time; copying a template and deleting all child entries but keeping the empty children key.","solutions":["Remove the empty children key from the document definition, or populate it with at least one child object.","If the top-level list is empty, add at least one document definition; parseTemplateDocTreeDefinition also enforces \"at least one document\".","Check the upstream data source/conditionals that produced an empty list and guard the createDocTree call on non-empty data.","Render-time: if children may be empty, build the definition conditionally so the children key is omitted entirely."],"exampleFix":"// before\n{\"title\": \"Parent\", \"children\": []}\n// after (omit children)\n{\"title\": \"Parent\"}","handlingStrategy":"validation","validationCode":"list, ok := def.([]any)\nif !ok || len(list) == 0 {\n    return errors.New(\"definition must be a non-empty array\")\n}\nvar walk func(nodes []any) error\nwalk = func(nodes []any) error {\n    for _, v := range nodes {\n        m, _ := v.(map[string]any)\n        if m == nil { continue }\n        if c, ok := m[\"children\"]; ok {\n            cl, ok := c.([]any)\n            if !ok || len(cl) == 0 {\n                return errors.New(\"children must be a non-empty array; omit the key instead\")\n            }\n            if err := walk(cl); err != nil { return err }\n        }\n    }\n    return nil\n}\nif err := walk(list); err != nil { return err }","typeGuard":"func nonEmptyList(v any) bool {\n    l, ok := v.([]any)\n    return ok && len(l) > 0\n}","tryCatchPattern":"nodes, err := parseTemplateDocTreeDefinition(def)\nif err != nil {\n    if strings.Contains(err.Error(), \"must not be empty\") {\n        // drop empty children keys or abort with a clear user message\n    }\n    return err\n}","preventionTips":["Omit the children key entirely when there are no children instead of using [].","Guard data-driven generation: skip the createDocTree call when the source list is empty.","Add a lint rule flagging empty children arrays in templates."],"tags":["template","empty-input","validation"],"backgroundTag":"empty-required-field","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"}