siyuan-note/siyuan · error
invalid block structure
Error message
invalid block structure: %s [%s] is not a content block
What it means
invalidBlockNodeError returns this message when the node exists but is not a content block (isContentBlock requires node.IsBlock() and excludes Kramdown IAL nodes). Placement/replacement validation only accepts actual content blocks as operands; markers such as IAL attribute nodes or non-block nodes are rejected. The node type and ID are included for diagnosis.
Solutions
- Skip Kramdown IAL / non-block nodes when resolving the target node (advance to the next node where node.IsBlock() is true)
- Use ID-based lookup (FindByID) rather than positional traversal to obtain the block node
- Check isContentBlock-equivalent conditions before calling the validator
Example fix
// before
node := tree.Root.Children[idx] // may be an IAL node
// after
node := tree.Root.Children[idx]
for nil != node && (!node.IsBlock() || ast.NodeKramdownBlockIAL == node.Type) {
node = node.Next
} Defensive patterns
Strategy: type-guard
Validate before calling
function isContentBlock(n) { return n != null && n.IsBlock === true && n.Type !== "NodeKramdownBlockIAL"; }
if (!isContentBlock(node)) throw new Error("target is not a content block"); Type guard
function isContentBlock(n) { return n != null && n.IsBlock === true && n.Type !== "NodeKramdownBlockIAL"; } Prevention
- When traversing AST children, skip IAL/marker nodes to land on real blocks
- Prefer ID-based lookups over positional indices
- Assert node type before passing it to placement APIs
When it happens
Trigger: Passing an IAL node, marker, or other non-block AST node as the parent/child to ValidateBlockPlacement/ValidateBlockReplacement; locating a node by position that lands on an IAL rather than the block itself.
Common situations: Plugin code traversing the AST by child index and hitting IAL nodes that follow block nodes; ID lookups resolving to structural markers after document edits.
Understand the failure class
Background: "Must be a positive integer", "Invalid value", "Unsupported": the invalid-argument-value error family, when a library rejects the value you pass — this error's family across 35 libraries.
Related errors
- invalid block structure
- block [ ] is not a document that can declare a child…
- document [ ] cannot be pinned
- heading [ ] is a leaf block and cannot have children; to…
- --id is required
AI-assisted analysis of siyuan-note/siyuan@9f775e8a12 (2026-09-19).
Data as JSON: /api/errors/70f124eff4cafedf.
Report an issue: GitHub.
Appendix: source
Thrown at kernel/treenode/block_structure.go:244
item.ListData.Marker = []byte(strconv.Itoa(num) + string(delimiter))
num++
}
}
func isContentBlock(node *ast.Node) bool {
return nil != node && node.IsBlock() && ast.NodeKramdownBlockIAL != node.Type
}
func invalidBlockContainmentError(parent, child *ast.Node) error {
return fmt.Errorf("invalid block structure: %s [%s] cannot contain %s [%s]",
parent.Type.String(), parent.ID, child.Type.String(), child.ID)
}
func invalidBlockNodeError(node *ast.Node) error {
if nil == node {
return fmt.Errorf("invalid block structure: block node is nil")
}
return fmt.Errorf("invalid block structure: %s [%s] is not a content block", node.Type.String(), node.ID)
}
View on GitHub (pinned to 9f775e8a12)