siyuan-note/siyuan · error
block [%s] is not a document
Error message
block [%s] is not a document
What it means
In GetDocBlocksOrders (blockinfo.go:558), after the tree for id is loaded and confirmed non-nil, the function checks tree.Root.ID != id and if so returns fmt.Errorf('block [%s] is not a document', id). This walker (getDocBlocksOrdersInTree) returns the ordered list of child block ids under a document root, so it must be given a document (root) id; passing any non-root block id is a caller error, not a data problem. ErrTreeNotFound is returned separately when the tree itself is missing.
Source
Thrown at kernel/model/blockinfo.go:569
for _, id := range ids {
ret[id] = nodesIndexes[id]
}
return
}
func GetDocBlocksOrders(id string) (ret []string, err error) {
ret = []string{}
tree, err := LoadTreeByBlockID(id)
if err != nil {
return
}
if nil == tree || nil == tree.Root {
err = ErrTreeNotFound
return
}
if tree.Root.ID != id {
err = fmt.Errorf("block [%s] is not a document", id)
return
}
ret = getDocBlocksOrdersInTree(tree)
return
}
func getDocBlocksOrdersInTree(tree *parse.Tree) (ret []string) {
ret = []string{}
ast.Walk(tree.Root, func(n *ast.Node, entering bool) ast.WalkStatus {
if !entering || n == tree.Root || !n.IsBlock() || ast.NodeKramdownBlockIAL == n.Type || "" == n.ID {
return ast.WalkContinue
}
ret = append(ret, n.ID)
return ast.WalkContinue
})
returnView on GitHub (pinned to 251596fc0d)
Solutions
- Resolve the id to its document root first via /api/block/getBlockInfo (rootID field) and pass that.
- On the client, derive the doc id from the open editor document rather than from the current selection.
- If you only have a child id, walk up: childID -> blockInfo.rootID -> getDocBlocksOrders(rootID).
Example fix
// before orders, err := model.GetDocBlocksOrders(childID) // after: resolve to the document root first rootID := treenode.GetBlockTree(childID).RootID orders, err := model.GetDocBlocksOrders(rootID)
Defensive patterns
Strategy: validation
Validate before calling
// Resolve a child id to its document root before asking for block orders.
bt := treenode.GetBlockTree(id)
docID := id
if bt != nil { docID = bt.RootID }
model.GetDocBlocksOrders(docID) Try / catch
// HTTP caller: on 'is not a document', resolve rootID and retry.
let r = await fetchSyncPost('/api/block/getDocBlocksOrders', {id})
if (r.code === -1 && /not a document/i.test(r.msg)) {
const info = await fetchSyncPost('/api/block/getBlockInfo', {id})
r = await fetchSyncPost('/api/block/getDocBlocksOrders', {id: info.data.rootID})
} Prevention
- Pass the open document's id, not the current selection's id.
- Resolve selection -> rootID once at call time instead of trusting the focus id.
When it happens
Trigger: POST /api/block/getDocBlocksOrders {id} with the id of a paragraph, heading, list, list-item, embed, or any other non-document block instead of the document root id.
Common situations: Caller confuses a block id with its document id; passes a selection/focus id straight through; copies a child id from a ref instead of resolving it to its root.
Related errors
- task list item marker length should be 1
- task list item marker can not be [ or ]
- custom emoji file is too large
- custom emoji file must not be empty
- invalid custom emoji image
AI-assisted analysis of siyuan-note/siyuan@251596fc0d (2026-08-12).
Data as JSON: /api/errors/d70b8b7912c59283.
Report an issue: GitHub.