{"record":{"id":"0a847da6ce9e7128","repo":"siyuan-note/siyuan","slug":"template-document-tree-plan-requires-a-parent-cont","errorCode":null,"errorMessage":"template document tree plan requires a parent content operation","messagePattern":"template document tree plan requires a parent content operation","errorType":"error_code","errorClass":null,"httpStatus":null,"severity":"error","filePath":"kernel/model/template_doc_tree.go","lineNumber":566,"sourceCode":"\tfor _, operation := range transaction.DoOperations {\n\t\tif nil == operation || \"\" == operation.ID {\n\t\t\treturn errors.New(\"template document tree plan contains an invalid parent operation\")\n\t\t}\n\t\tinverseAction, supported := inverseActions[operation.Action]\n\t\tif !supported || \"\" != operation.RootID {\n\t\t\treturn errors.New(\"template document tree plan contains an unsupported parent operation\")\n\t\t}\n\t\tif \"insert\" == operation.Action || \"delete\" == operation.Action || \"update\" == operation.Action {\n\t\t\thasContentMutation = true\n\t\t}\n\t\tkey := inverseAction + \"\\x00\" + operation.ID\n\t\tif 1 > undoOperations[key] {\n\t\t\treturn errors.New(\"template document tree plan parent operations are not reversible\")\n\t\t}\n\t\tundoOperations[key]--\n\t}\n\tif !hasContentMutation {\n\t\treturn errors.New(\"template document tree plan requires a parent content operation\")\n\t}\n\tfor _, count := range undoOperations {\n\t\tif 0 != count {\n\t\t\treturn errors.New(\"template document tree plan parent operations are not reversible\")\n\t\t}\n\t}\n\treturn nil\n}\n\nfunc transactionTargetsTemplateRoot(transaction *Transaction, rootID, boxID string) bool {\n\tmatched := false\n\tfor operationSetIndex, operations := range [][]*Operation{transaction.DoOperations, transaction.UndoOperations} {\n\t\tfor _, operation := range operations {\n\t\t\tif nil == operation {\n\t\t\t\tcontinue\n\t\t\t}\n\t\t\tids := []string{operation.ID}\n\t\t\tif \"insert\" == operation.Action {","sourceCodeStart":548,"sourceCodeEnd":584,"githubUrl":"https://github.com/siyuan-note/siyuan/blob/8641553a1f07374001902d3ce773285db1292b2d/kernel/model/template_doc_tree.go#L548-L584","documentation":"This error comes from validateTemplateDocTreeParentOperations, an internal consistency check on a template-document-tree plan transaction in SiYuan's kernel. A plan's transaction must not only pair every DoOperation with a matching UndoOperation, it must also include at least one parent-level content mutation (insert, delete, or update). If the transaction only contains non-content operations (foldHeading/unfoldHeading/setAttrs) or is empty of content mutations, the kernel rejects it because the plan cannot be applied as an undoable document change.","triggerScenarios":"AttachTemplateDocTreePlans builds a transaction whose DoOperations/UndoOperations all use foldHeading, unfoldHeading, or setAttrs (no insert/delete/update on parent blocks), or a caller attaches a plan with an empty/operation-less transaction, so hasContentMutation stays false.","commonSituations":"Kernel-side or plugin-driven automation that applies a rendered template doc tree plan but pairs it only with attribute/fold state changes instead of actual block edits; internal invariant breakage after refactoring the plan/transaction builder; replaying a hand-crafted transaction missing content operations.","solutions":["Ensure the transaction attaching the plan includes at least one insert, delete, or update operation on a block in the target document","Verify the code path building DoOperations/UndoOperations sets content-mutation actions, not only foldHeading/unfoldHeading/setAttrs","Re-render the template plan so the plan contains real document changes, then re-attach","If this appears without custom transaction code, report it as an internal invariant violation with reproduction steps"],"exampleFix":"// before: only non-content ops\ntxn.DoOperations = []*Operation{{Action: \"setAttrs\", ID: blockID}}\n// after: include a content mutation\ntxn.DoOperations = []*Operation{{Action: \"update\", ID: blockID}, {Action: \"setAttrs\", ID: blockID}}","handlingStrategy":"validation","validationCode":"hasContent := false\nfor _, op := range txn.DoOperations {\n\tif op.Action == \"insert\" || op.Action == \"delete\" || op.Action == \"update\" {\n\t\thasContent = true\n\t}\n}\nif !hasContent {\n\treturn errors.New(\"plan transaction needs at least one insert/delete/update parent operation\")\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Always pair plan attachment with at least one content-mutating operation on the target document","Never build plan transactions using only foldHeading/unfoldHeading/setAttrs","Add a unit test asserting plan transactions contain a content mutation before AttachTemplateDocTreePlans"],"tags":["go","kernel","transactions","internal"],"backgroundTag":"internal-invariant-violation","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"}