siyuan-note/siyuan · error

template document tree parent snapshot is invalid

Error message

template document tree parent snapshot is invalid

What it means

When committing a transaction that creates a document from a template, the kernel loads the parent document tree snapshot referenced by templateDocTreeRootID. If the load call succeeds but returns a nil tree (the lookup found nothing while reporting no error), the kernel treats the parent reference as invalid and fails the commit with this error.

Source

Thrown at kernel/model/transaction.go:2624

			if existingBox, exists := tx.restoredCreatedDocBoxes[operation.ID]; exists {
				if existingBox != operation.Tree.Box {
					tx.restoredCreatedDocBoxes[operation.ID] = ""
				}
			} else {
				tx.restoredCreatedDocBoxes[operation.ID] = operation.Tree.Box
			}
		}
		if ("restoreCreatedDoc" != operation.Action && "removeCreatedDoc" != operation.Action) ||
			"" == operation.templateDocTreeRootID || nil == operation.Tree {
			continue
		}
		if nil == tx.templateDocTreeRootSnapshot {
			snapshot, loadErr := LoadTreeByBlockID(operation.templateDocTreeRootID)
			if nil != loadErr {
				return fmt.Errorf("load template document tree parent snapshot failed: %w", loadErr)
			}
			if nil == snapshot {
				return errors.New("template document tree parent snapshot is invalid")
			}
			if nil != expectedTemplateDocTreeRoot &&
				(expectedTemplateDocTreeRoot.ID != snapshot.ID || expectedTemplateDocTreeRoot.Box != snapshot.Box ||
					expectedTemplateDocTreeRoot.Path != snapshot.Path || expectedTemplateDocTreeRoot.HPath != snapshot.HPath) {
				return errors.New("the document used to render the template has changed")
			}
			tx.templateDocTreeRootSnapshot = snapshot
		}
		if nil == tx.templateDocTreeRootSnapshot || tx.templateDocTreeRootSnapshot.ID != operation.templateDocTreeRootID ||
			tx.templateDocTreeRootSnapshot.Box != operation.Tree.Box {
			return errors.New("template document tree parent snapshot is invalid")
		}
	}
	tx.listItemFoldCandidates = nil
	tx.listItemFoldCandidateIDs = map[string]struct{}{}
	tx.deletedAttrViewBlockIDs = map[string]map[string]struct{}{}
	tx.structureCheckNodes = map[*ast.Node]struct{}{}
	tx.crossTreeMoveRefRefreshes = nil

View on GitHub (pinned to 8641553a1f)

Solutions

  1. Refresh/reindex the notebook so the index agrees with the .sy files on disk, then retry the operation
  2. Re-create the document from the template in the current UI state so a live parent document reference is used
  3. Check that the parent document referenced still exists and has not been deleted by another client or sync
Defensive patterns

Strategy: try-catch

Validate before calling

const doc = await fetchPost('/api/filetree/getDoc', {id: parentRootId});
if (doc.code !== 0 || !doc.data) throw new Error('parent snapshot unavailable');

Try / catch

try {
  await commitTemplateCreation(tx);
} catch (e) {
  if (String(e.message).includes('parent snapshot is invalid')) {
    await reindexNotebook(boxId);
    await commitTemplateCreation(tx); // retry after index refresh
  } else { throw e; }
}

Prevention

When it happens

Trigger: A doRestoreCreatedDoc operation's templateDocTreeRootID points to a block/tree that LoadTreeByBlockID cannot resolve (returns nil, nil) — typically because the referenced document or block no longer exists in the index.

Common situations: The parent document was deleted or its root block changed after the template render but before commit; an out-of-sync index reports no tree for a valid ID; concurrent sync removed the document mid-transaction.

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


AI-assisted analysis of siyuan-note/siyuan@8641553a1f (2026-09-11). Data as JSON: /api/errors/0d5bd12105af4ede. Report an issue: GitHub.