{"record":{"id":"9c086c57710e9298","repo":"siyuan-note/siyuan","slug":"invalid-block-structure-s-s-cannot-contain-s","errorCode":null,"errorMessage":"invalid block structure: %s [%s] cannot contain %s [%s]","messagePattern":"invalid block structure: (.+?) \\[(.+?)\\] cannot contain (.+?) \\[(.+?)\\]","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"kernel/treenode/block_structure.go","lineNumber":236,"sourceCode":"\t\t\tcontinue\n\t\t}\n\t\tif nil == item.ListData {\n\t\t\titem.ListData = &ast.ListData{}\n\t\t}\n\t\titem.ListData.Typ = 1\n\t\titem.ListData.Num = num\n\t\titem.ListData.Delimiter = delimiter\n\t\titem.ListData.Marker = []byte(strconv.Itoa(num) + string(delimiter))\n\t\tnum++\n\t}\n}\n\nfunc isContentBlock(node *ast.Node) bool {\n\treturn nil != node && node.IsBlock() && ast.NodeKramdownBlockIAL != node.Type\n}\n\nfunc invalidBlockContainmentError(parent, child *ast.Node) error {\n\treturn fmt.Errorf(\"invalid block structure: %s [%s] cannot contain %s [%s]\",\n\t\tparent.Type.String(), parent.ID, child.Type.String(), child.ID)\n}\n\nfunc invalidBlockNodeError(node *ast.Node) error {\n\tif nil == node {\n\t\treturn fmt.Errorf(\"invalid block structure: block node is nil\")\n\t}\n\treturn fmt.Errorf(\"invalid block structure: %s [%s] is not a content block\", node.Type.String(), node.ID)\n}\n","sourceCodeStart":218,"sourceCodeEnd":246,"githubUrl":"https://github.com/siyuan-note/siyuan/blob/9f775e8a12daef8255556097396f9b2739078892/kernel/treenode/block_structure.go#L218-L246","documentation":"invalidBlockContainmentError reports that a parent block of a given AST type cannot structurally contain the proposed child block. The tree validator (ValidateBlockPlacement / ValidateBlockReplacement) enforces SiYuan's document model constraints — e.g. a heading cannot have child nodes in the AST, a paragraph cannot contain blocks. The error includes both node types and IDs so the offending pair is identifiable.","triggerScenarios":"Inserting or replacing blocks where the target parent's AST type disallows the child type — e.g. passing parentID of a heading or paragraph as the container for a new child block via the editor transaction APIs or blockInsert.","commonSituations":"Plugins calling insert APIs with an arbitrary parentID (often a heading, expecting heading-child semantics); drag-and-drop moves computed by custom UI; programmatic document generation that nests blocks illegally.","solutions":["Choose a legal parent: a container type (list item, blockquote, super block, document) for the child type","For placing content under a heading, insert as a SIBLING after the heading (previousID = heading id) instead of using it as parentID","Wrap the child in a structurally legal container if the target position requires nesting"],"exampleFix":"// before\nawait insertBlock({ parentID: headingID, data: '<div data-type=\"NodeParagraph\">x</div>' }) // heading cannot contain\n// after\nawait insertBlock({ previousID: headingID, data: '<div data-type=\"NodeParagraph\">x</div>' }) // insert as sibling","handlingStrategy":"validation","validationCode":"const CONTAINER_TYPES = new Set([\"list\", \"listitem\", \"blockquote\", \"super\", \"document\"]);\nif (!CONTAINER_TYPES.has(parentType)) throw new Error(\"parent is not a container\");","typeGuard":"function isBlockNode(n) { return n != null && n.IsBlock === true && n.Type !== \"NodeKramdownBlockIAL\"; }","tryCatchPattern":"try {\n  await insertBlock({ parentID, data });\n} catch (e) {\n  if (String(e.message).startsWith(\"invalid block structure\")) console.error(\"Illegal parent/child pair:\", e.message);\n  else throw e;\n}","preventionTips":["Know SiYuan block types before nesting: headings and paragraphs are leaves","Use previousID for content that should follow a heading","Fetch block type via getBlockInfo before choosing parentID"],"tags":["document","structure","validation"],"backgroundTag":"incompatible-source-type","analyzedSha":"9f775e8a12daef8255556097396f9b2739078892","analyzedAt":"2026-09-19T03:17:15.984Z","contentChangedAt":"2026-09-19T03:17:15.984Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}