siyuan-note/siyuan · warning
list block has no list item
Error message
list block has no list item
What it means
Returned by resolveBlockUpdateNode. The old node is a NodeListItem and the updated node resolved to a NodeList (the user submitted list markup), so the code looks for a NodeListItem inside the list via firstContentBlock. If none exists or it isn't a NodeListItem, the list is malformed - a list with no list item cannot replace a list item.
Source
Thrown at kernel/model/block_update.go:249
updatedNode.Unlink()
root := &ast.Node{Type: ast.NodeDocument}
root.AppendChild(updatedNode)
ret = &parse.Tree{
Root: root,
Context: &parse.Context{ParseOption: luteEngine.ParseOptions},
}
return
}
func resolveBlockUpdateNode(oldNode, root *ast.Node) (updatedNode *ast.Node, err error) {
updatedNode = firstContentBlock(root)
if nil == updatedNode {
return nil, errors.New("parse tree failed")
}
if ast.NodeListItem == oldNode.Type && ast.NodeList == updatedNode.Type {
listItem := firstContentBlock(updatedNode)
if nil == listItem || ast.NodeListItem != listItem.Type {
return nil, errors.New("list block has no list item")
}
updatedNode = listItem
}
return
}
// pinDescendantBlockIDs 把旧块子树中对应位置的子块 ID 钉回新块,避免更新容器块时 Lute 重新生成
// 子块 ID,导致指向子块的块引用、反链、闪卡等失效。
// 匹配规则:按同级内容块顺序对齐,类型一致才沿用旧 ID;类型不一致时向后查找同类型的旧子块重新
// 对齐,这样插入或删除子块后其余子块仍能匹配上旧 ID,新增的子块保持新生成的 ID。
func pinDescendantBlockIDs(oldNode, updatedNode *ast.Node) {
oldChildren := blockChildrenOf(oldNode)
oldIndex := 0
for _, newChild := range blockChildrenOf(updatedNode) {
if oldIndex >= len(oldChildren) {
break
}
if oldChildren[oldIndex].Type != newChild.Type {View on GitHub (pinned to 251596fc0d)
Solutions
- Ensure the list input contains at least one non-empty list item (e.g. "- item").
- Validate the parsed tree has a NodeListItem child before submitting when updating a list item.
- If the intent is to delete the item, call the delete API instead of submitting an empty list.
Example fix
// before // input.Data = "- " // after // input.Data = "- actual content"
Defensive patterns
Strategy: validation
Validate before calling
// when updating a list item, ensure the markdown has at least one item with content
if oldNodeIsListItem && !regexp.MustCompile(`^[-*+]\s+\S`).MatchString(strings.TrimSpace(input.Data)) {
return errors.New("list input has no list item with content")
} Prevention
- Ensure list input has at least one non-empty list item.
- Use the delete API when the intent is to remove the item, not submit an empty list.
- Validate parsed tree has a NodeListItem child before submitting list updates.
When it happens
Trigger: Updating a list item with markdown/dom that produces an empty list (e.g. "- " with no content) or a list whose only child is another nested list; submitting "* " alone.
Common situations: Client sending placeholder list syntax; markdown stripped of its item content in transit; Lute producing a NodeListBox without a child item from degenerate input.
Related errors
- found invalid ID [%s]
- block updates are empty
- invalid block ID [%s]
- data block DOM failed: %w
- unsupported block data type [%s]
AI-assisted analysis of siyuan-note/siyuan@251596fc0d (2026-08-12).
Data as JSON: /api/errors/8743ffdf3bf29bae.
Report an issue: GitHub.