siyuan-note/siyuan · error

the document used to render the template has changed

Error message

the document used to render the template has changed

What it means

A transaction creating a document from a template records the parent document tree state expected at render time. At commit, the freshly loaded snapshot is compared (ID, Box, Path, HPath) against that expectation; if any differ, the underlying document was moved, renamed, or replaced while the transaction was being built, so the commit is refused to avoid writing into an inconsistent location.

Source

Thrown at kernel/model/transaction.go:2629

				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
	tx.luteEngine = util.NewLute()
	tx.m.Lock()
	tx.state.Store(1)
	return
}

View on GitHub (pinned to 8641553a1f)

Solutions

  1. Refresh the document tree in the UI and retry the template insertion against the current state
  2. Avoid renaming/moving the parent document while a template-based creation is pending
  3. Check sync history to see if a remote change moved the document, then re-perform the action on the moved document
Defensive patterns

Strategy: retry

Validate before calling

const cur = await fetchPost('/api/filetree/getDoc', {id: expectedRootId});
if (cur.data.path !== expectedPath || cur.data.box !== expectedBox) {
  throw new Error('parent document has moved; refresh before inserting template');
}

Try / catch

try {
  await insertTemplateDoc(parentId, tpl);
} catch (e) {
  if (String(e.message).includes('document used to render the template has changed')) {
    await reloadDocTree();
    await insertTemplateDoc(currentParentId, tpl); // retry with current parent
  } else { throw e; }
}

Prevention

When it happens

Trigger: Committing a template-created-doc transaction whose expectedTemplateDocTreeRoot (ID/Box/Path/HPath) no longer matches the current on-disk parent tree — the parent doc was renamed, moved to another notebook, or its path changed between render and commit.

Common situations: User renames the parent document or drags it to another notebook while the template insertion is pending; sync applies a remote rename to the same document; two windows have divergent views of the same doc.

Understand the failure class

Background: "Invalid state transition" errors: "status must be X, actually Y", "already rejected/charging/uninstalled", "cannot ... while running" — what they mean when a library rejects your call — this error's family across 31 libraries.

Related errors


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