siyuan-note/siyuan · error
localized block-not-found message (Conf.Language(15)) with b
Error message
localized block-not-found message (Conf.Language(15)) with block ID
What it means
GetHeadingDeleteTransaction builds the transaction that removes a heading and its children. Before inspecting the node it looks the block up in the parsed tree; if no node exists for the given ID it returns the localized block-not-found message (Conf.Language(15)) formatted with the block ID. The heading ID does not correspond to any existing block in the document tree.
Source
Thrown at kernel/model/block.go:843
if !sameTree {
if err = indexWriteTreeUpsertQueue(defTree); err != nil {
return
}
}
FlushTxQueue()
util.ReloadUI()
return
}
func GetHeadingDeleteTransaction(id string) (transaction *Transaction, err error) {
tree, err := LoadTreeByBlockID(id)
if err != nil {
return
}
node := treenode.GetNodeInTree(tree, id)
if nil == node {
err = fmt.Errorf(Conf.Language(15), id)
return
}
if ast.NodeHeading != node.Type {
return
}
var nodes []*ast.Node
nodes = append(nodes, node)
nodes = append(nodes, treenode.HeadingChildren(node)...)
hiddenNodes := map[string]bool{}
for _, hidden := range treenode.CollectFoldHiddenNodes(node.Parent) {
hiddenNodes[hidden.ID] = true
}
transaction = &Transaction{}
luteEngine := util.NewLute()
for _, n := range nodes {View on GitHub (pinned to 8641553a1f)
Solutions
- Refresh the block ID from the current document (re-read the block via SQL/API) before calling the transaction builder
- Confirm the document tree is indexed correctly (rebuild the index for the notebook if .sy files were edited externally)
- Check that the ID is a valid 14-character node ID and belongs to the intended box/doc
- If concurrent modification is possible, re-run the operation after syncing/reloading the document
Example fix
// before
ops, err := GetHeadingDeleteTransaction(staleHeadingID)
// after
if !treenode.IsNodeExist(staleHeadingID) { // or re-query the block first
return fmt.Errorf("heading %s no longer exists; refresh ID", staleHeadingID)
}
ops, err := GetHeadingDeleteTransaction(staleHeadingID) Defensive patterns
Strategy: validation
Validate before calling
// before building the delete transaction
if (!blockExists(headingID)) {
throw new Error(`heading ${headingID} no longer exists`);
} Type guard
function hasNode(id) {
return typeof id === "string" && /^\d{14}$/.test(id) && treeHasNode(id);
} Prevention
- Re-resolve block IDs from the live document immediately before transactions
- Reindex notebooks after any external .sy modification
- Avoid caching block IDs across long-running operations or syncs
When it happens
Trigger: Calling GetHeadingDeleteTransaction (directly or via getHeadingDeleteTransaction) with a heading ID that no longer exists — the block was deleted in another session, the ID is mistyped, or the .sy file changed on disk without reindexing.
Common situations: Stale block IDs held by plugins/scripts after content changed, concurrent edits removing the heading, corrupted or manually edited .sy files, or a race between fetching the ID and building the transaction.
Understand the failure class
Background: 'Could not be found', 'does not exist', 'not found in database': the resource-not-found family when an ID, slug, key, or URI lookup comes back empty — this error's family across 20 libraries.
Related errors
- tree not found
- load block tree [%s] failed: %w
- load block tree [%s] failed: tree is empty
- ErrTreeNotFound
- load tree failed: %s
AI-assisted analysis of siyuan-note/siyuan@8641553a1f (2026-09-11).
Data as JSON: /api/errors/6842ac17c6a1f274.
Report an issue: GitHub.