siyuan-note/siyuan · error
block [%s] not found
Error message
block [%s] not found
What it means
Returned by buildBlockUpdateOperations when loadTree succeeded with a non-empty Root, but treenode.GetNodeInTree(oldTree, input.ID) returned nil. The tree is fine; the specific block ID is not a node in it - same desync class as the block.go not-found errors, but inside the update pipeline.
Source
Thrown at kernel/model/block_update.go:125
oldTree = treeCache[cacheKey]
}
if nil == oldTree {
var loadErr error
oldTree, loadErr = loadTree(input.ID)
if loadErr != nil {
return nil, nil, fmt.Errorf("load block tree [%s] failed: %w", input.ID, loadErr)
}
if nil == oldTree || nil == oldTree.Root {
return nil, nil, fmt.Errorf("load block tree [%s] failed: tree is empty", input.ID)
}
treeCache[blockUpdateTreeKey{boxID: oldTree.Box, rootID: oldTree.ID}] = oldTree
if hasCacheKey {
treeCache[cacheKey] = oldTree
}
}
oldNode := treenode.GetNodeInTree(oldTree, input.ID)
if nil == oldNode {
return nil, nil, fmt.Errorf("block [%s] not found", input.ID)
}
if _, ok := rootIDSet[oldTree.ID]; !ok {
rootIDSet[oldTree.ID] = struct{}{}
rootIDs = append(rootIDs, oldTree.ID)
}
if ast.NodeDocument == oldNode.Type {
if validateErr := treenode.ValidateBlockSubtree(dataTree.Root); validateErr != nil {
return nil, nil, validateErr
}
for n := oldTree.Root.FirstChild; nil != n; n = n.Next {
if !n.IsBlock() || ast.NodeKramdownBlockIAL == n.Type {
continue
}
operations = append(operations, &Operation{Action: "delete", ID: n.ID, Data: map[string]any{
"createEmptyParagraph": false, // 清空文档后前端不要创建空段落
}})View on GitHub (pinned to 251596fc0d)
Solutions
- Rebuild the index to reconcile blocktree.db with on-disk trees.
- Verify via SQL that the block ID still maps to the expected root ID.
- Reload the document and re-issue the update with a current block ID.
- Retry once if a concurrent transaction is plausible; if it persists, surface 'block gone' to the user.
Defensive patterns
Strategy: validation
Validate before calling
row, _ := sql.QueryRow("SELECT root_id FROM blocks WHERE id = ?", input.ID)
// confirm input.ID is still mapped to a node in its tree before update Try / catch
ops, roots, err := buildBlockUpdateOperations(inputs, resolver, loader)
if err != nil && strings.Contains(err.Error(), "not found") {
// reload document, refresh block IDs, retry
} Prevention
- Reload the document before updates that target specific block IDs.
- Rebuild the index after sync to remove stale blocktree entries.
- Verify the block still belongs to its expected root via SQL.
When it happens
Trigger: Block was moved/deleted between resolveTree's view and the load; blocktree entry points at a tree that no longer hosts the block; concurrent transaction rewrote the tree.
Common situations: Sync conflict; another client edited the document; blocktree lag after a recent move operation.
Related errors
- Content block with id [%s] not found
- block not found: %s
- previous block not found: %s
- document not found: %s
- document not found: <documentID>
AI-assisted analysis of siyuan-note/siyuan@251596fc0d (2026-08-12).
Data as JSON: /api/errors/ecf09791c3c95326.
Report an issue: GitHub.