siyuan-note/siyuan · error · ErrBlockNotFound
block not found
Error message
block not found
What it means
Sentinel error ErrBlockNotFound declared at tree.go:204 ('block not found'). The most widely thrown sentinel — returned by heading/block/assets/search/transaction/template operations when a block ID has no blocktree entry (treenode.GetBlockTree returns nil). Callers compare with errors.Is(err, model.ErrBlockNotFound). Throw sites include heading.go (many), block.go, assets.go:1216, search.go, transaction.go (TxErr wrapping), template.go:382.
Source
Thrown at kernel/model/tree.go:204
relPath := filepath.ToSlash(strings.TrimPrefix(localPath, filepath.Join(util.DataDir, boxID)+string(os.PathSeparator)))
if data, err = DecryptFile(boxID, relPath, dek, data); err != nil {
logging.LogErrorf("decrypt tree [path=%s] failed: %s", localPath, err)
return
}
}
ret, err = dataparser.ParseJSONWithoutFix(data, luteEngine.ParseOptions)
if err != nil {
logging.LogErrorf("parse json to tree [%s] failed: %s", localPath, err)
return
}
return
}
var (
ErrBoxNotFound = errors.New("notebook not found")
ErrBoxClosed = errors.New("notebook closed")
ErrBlockNotFound = errors.New("block not found")
ErrTreeNotFound = errors.New("tree not found")
ErrIndexing = errors.New("indexing")
ErrBoxUnindexed = errors.New("notebook unindexed")
ErrInvalidID = errors.New("invalid id")
)
func LoadTreeByBlockIDWithReindex(id string) (ret *parse.Tree, err error) {
return LoadTreeByBlockIDWithReindexInBox(id, "")
}
// LoadTreeByBlockIDWithReindexInBox 与 LoadTreeByBlockIDWithReindex 一致,但按 boxID 路由 blocktree 查询。
func LoadTreeByBlockIDWithReindexInBox(id, boxID string) (ret *parse.Tree, err error) {
if "" == id {
logging.LogWarnf("block id is empty")
return nil, ErrTreeNotFound
}
bt := treenode.GetBlockTreeInBox(id, boxID)View on GitHub (pinned to 251596fc0d)
Solutions
- Validate the block ID exists via treenode.GetBlockTree(id) before the operation.
- If the blocktree is suspected out of sync, trigger a reindex of the notebook.
- For UI references, detect ErrBlockNotFound and offer to remove/repair the dangling reference.
- Use errors.Is(err, model.ErrBlockNotFound) — never string-match the message.
Example fix
// before — assume block exists
bt := treenode.GetBlockTree(id)
operateOnBlock(bt) // nil panic or ErrBlockNotFound
// after — guard
bt := treenode.GetBlockTree(id)
if bt == nil {
return ErrBlockNotFound
} Defensive patterns
Strategy: validation
Validate before calling
func blockExists(id string) bool {
return treenode.GetBlockTree(id) != nil
} Try / catch
err := op(blockID)
if errors.Is(err, model.ErrBlockNotFound) {
// offer to repair/remove the dangling reference
} Prevention
- Validate block IDs via treenode.GetBlockTree before block-scoped operations.
- If blocktree seems stale, reindex the notebook.
- Use errors.Is(err, model.ErrBlockNotFound) for precise branching.
When it happens
Trigger: Referencing a block ID that was deleted, never existed, or whose blocktree entry was lost; a block-ref/heading operation on a stale ID; an AV operation referencing a missing block; transaction processing where an ID in the tx no longer resolves.
Common situations: A block was deleted but a reference (block-ref, heading fold, bookmark) still points to it; the blocktree.db is corrupted or out of sync with the .sy files; a plugin passes an invalid or truncated block ID; cross-workspace reference where the target block is absent.
Related errors
- notebook not found
- tree not found
- parent block not found: %s
- block not found: %s
- previous block not found: %s
AI-assisted analysis of siyuan-note/siyuan@251596fc0d (2026-08-12).
Data as JSON: /api/errors/07e8c4938ec04ccd.
Report an issue: GitHub.