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

  1. Skip Kramdown IAL / non-block nodes when resolving the target node (advance to the next node where node.IsBlock() is true)
  2. Use ID-based lookup (FindByID) rather than positional traversal to obtain the block node
  3. 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 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


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)