{"record":{"id":"6683fa34f3943804","repo":"siyuan-note/siyuan","slug":"createdoctree-document-template-and-define-are-mut","errorCode":null,"errorMessage":"createDocTree document template and define are mutually exclusive","messagePattern":"createDocTree document template and define are mutually exclusive","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"kernel/model/template_doc_tree.go","lineNumber":172,"sourceCode":"\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 {\n\t\t\treturn nil, errors.New(\"createDocTree document template and define are mutually exclusive\")\n\t\t}\n\n\t\tstate.count++\n\t\tif maxTemplateDocTreeDocs < state.count {\n\t\t\treturn nil, fmt.Errorf(\"createDocTree exceeds the maximum document count of %d\", maxTemplateDocTreeDocs)\n\t\t}\n\t\tid := ast.NewNodeID()\n\t\tnode := &TemplateDocTreeNode{\n\t\t\tID:       id,\n\t\t\tRootID:   id,\n\t\t\tTitle:    title,\n\t\t\tDepth:    depth,\n\t\t\tTemplate: templateName,\n\t\t\tDefine:   defineName,\n\t\t}\n\t\tif childrenValue, exists := definition[\"children\"]; exists {\n\t\t\tchildren, parseErr := state.parseNodes(childrenValue, depth+1)\n\t\t\tif nil != parseErr {","sourceCodeStart":154,"sourceCodeEnd":190,"githubUrl":"https://github.com/siyuan-note/siyuan/blob/8641553a1f07374001902d3ce773285db1292b2d/kernel/model/template_doc_tree.go#L154-L190","documentation":"A createDocTree document may specify how its content is produced either by referencing an existing template file (template) or by an inline define block, but not both. Supplying both non-empty template and define fields is ambiguous and rejected by parseNodes.","triggerScenarios":"A document object like {\"title\": \"X\", \"template\": \"note.md\", \"define\": \"...\"}; merging two definition styles when refactoring; copy-pasting fields from two different example documents into one.","commonSituations":"Authors unsure of the two mechanisms adding both to be safe; generated definitions that always emit both keys with defaults; editing a template-based entry to inline content while forgetting to delete the template field.","solutions":["Keep only one content source: delete the template field to use the inline define, or delete define to use the template file.","If both behaviors are wanted, nest documents: one child with template and a sibling child with define.","In generated definitions, emit template XOR define based on which source is available.","Pre-validate: reject any node where both fields are non-empty strings before rendering."],"exampleFix":"// before\n{\"title\": \"Daily\", \"template\": \"daily.md\", \"define\": \"content here\"}\n// after (use define)\n{\"title\": \"Daily\", \"define\": \"content here\"}","handlingStrategy":"validation","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        tpl, _ := m[\"template\"].(string)\n        def, _ := m[\"define\"].(string)\n        if tpl != \"\" && def != \"\" {\n            return errors.New(\"template and define are mutually exclusive on one document\")\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 hasOneContentSource(v any) bool {\n    m, ok := v.(map[string]any)\n    if !ok { return false }\n    tpl, _ := m[\"template\"].(string)\n    def, _ := m[\"define\"].(string)\n    return tpl == \"\" || def == \"\"\n}","tryCatchPattern":"nodes, err := parseTemplateDocTreeDefinition(def)\nif err != nil {\n    if strings.Contains(err.Error(), \"mutually exclusive\") {\n        // drop template or define on the offending node and retry\n    }\n    return err\n}","preventionTips":["Pick one content mechanism per document: file template OR inline define.","In generators, emit template XOR define based on availability.","When converting a template-based entry to inline content, delete the template field in the same edit."],"tags":["template","conflicting-options","validation"],"backgroundTag":"mutually-exclusive-options","analyzedSha":"8641553a1f07374001902d3ce773285db1292b2d","analyzedAt":"2026-09-11T16:08:28.414Z","contentChangedAt":"2026-09-11T16:08:28.414Z","schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}