siyuan-note/siyuan · error
invalid created doc compensation snapshot
Error message
invalid created doc compensation snapshot
What it means
restoreCreatedDocTreeSnapshot compensates a failed transaction by restoring the tree of a document that was created within it. It throws this error when it is handed a nil tree or a tree with a nil Root, which means the compensation snapshot passed to the transaction rollback path is unusable and the created document's tree cannot be re-persisted.
Source
Thrown at kernel/model/transaction.go:2871
}
if restoreErr := restoreCreatedDocTreeSnapshot(tree); nil != restoreErr {
err = errors.Join(err, restoreErr)
continue
}
if box := Conf.Box(tree.Box); nil != box {
box.setSortByConf(path.Dir(tree.Path), tree.ID)
PushCreate(box, tree.Path, nil)
}
}
if nil != tx.templateDocTreeRootSnapshot {
err = errors.Join(err, restoreCreatedDocTreeSnapshot(tx.templateDocTreeRootSnapshot))
}
return
}
func restoreCreatedDocTreeSnapshot(tree *parse.Tree) error {
if nil == tree || nil == tree.Root {
return errors.New("invalid created doc compensation snapshot")
}
if err := writeTreeUpsertQueue(tree); nil != err {
return err
}
treenode.UpsertBlockTree(tree)
return nil
}
func (tx *Transaction) loadTreeByBlockTree(bt *treenode.BlockTree) (ret *parse.Tree, err error) {
if nil == bt {
return nil, ErrBlockNotFound
}
ret = tx.trees[bt.RootID]
if nil != ret {
return
}
View on GitHub (pinned to 8641553a1f)
Solutions
- Ensure the created document's tree is loaded/parsed successfully before initiating the transaction compensation, and skip or log when no tree exists
- Check that the .sy file for the created doc exists and is valid JSON Kramdown in the notebook's data directory
- Re-open the notebook / rebuild the index so the tree can be re-fetched, then retry the transaction
- Inspect the caller of restoreCreatedDocTreeSnapshot to make sure it does not forward a nil tree from a failed load without handling it
Example fix
// before
restoreCreatedDocTreeSnapshot(tree)
// after
if tree != nil && tree.Root != nil {
if err := restoreCreatedDocTreeSnapshot(tree); err != nil {
logging.LogErrorf("restore created doc snapshot failed: %v", err)
}
} Defensive patterns
Strategy: type-guard
Validate before calling
if tree == nil || tree.Root == nil {
return errors.New("cannot compensate: snapshot tree is empty")
}
restoreCreatedDocTreeSnapshot(tree) Type guard
func hasRoot(tree *parse.Tree) bool { return tree != nil && tree.Root != nil } Prevention
- Never pass a tree obtained from a loader that may return nil into compensation paths without checking
- Log and handle tree load failures before entering the transaction rollback
- Validate .sy files after restore/import before running transactions
When it happens
Trigger: A transaction includes a document creation, later fails, and the compensation path calls restoreCreatedDocTreeSnapshot with a nil tree or a parse.Tree whose Root is nil (e.g. the tree failed to load/parse before the compensation ran).
Common situations: Rollback after a partial multi-doc transaction where the created doc's tree was never indexed; corrupted or not-yet-written .sy file loaded into a tree with no root; a nil result from a tree loader passed straight into the compensation function.
Understand the failure class
Background: "This is a bug, please report it": internal invariant violations, unreachable panics, and SNH errors explained — this error's family across 47 libraries.
Related errors
- install local marketplace package failed: %w; rollback faile
- attribute view is required
- %w; cleanup failed: %v
- can not get or create rollback box
- Conf.Language(314)
AI-assisted analysis of siyuan-note/siyuan@8641553a1f (2026-09-11).
Data as JSON: /api/errors/891cd89ed830f41a.
Report an issue: GitHub.