siyuan-note/siyuan · error

template document tree plan does not match the edited docume

Error message

template document tree plan does not match the edited document

What it means

transactionTargetsTemplateRoot verifies that the transaction's Do/Undo operations actually target the template root document recorded in the plan (plan.rootID/plan.boxID). This error means the plan was rendered from a different document than the one the transaction edits — the plan and transaction are mismatched.

Source

Thrown at kernel/model/template_doc_tree.go:489

	}
	for _, operation := range append(append([]*Operation{}, target.DoOperations...), target.UndoOperations...) {
		if nil != operation && ("restoreCreatedDoc" == operation.Action || "removeCreatedDoc" == operation.Action) {
			return false, errors.New("template document tree transaction contains a reserved operation")
		}
	}

	planID := target.TemplateDocTreePlanID
	target.TemplateDocTreePlanID = ""
	value, loaded := templateDocTreePlans.LoadAndDelete(planID)
	if !loaded {
		return false, errors.New("template document tree plan is missing or has expired")
	}
	plan, ok := value.(*templateDocTreePlan)
	if !ok || plan.id != planID || time.Now().After(plan.expiresAt) {
		return false, errors.New("template document tree plan is invalid or has expired")
	}
	if !transactionTargetsTemplateRoot(target, plan.rootID, plan.boxID) {
		return false, errors.New("template document tree plan does not match the edited document")
	}
	rootTree, loadErr := LoadTreeByBlockID(plan.rootID)
	if nil != loadErr || nil == rootTree || rootTree.Box != plan.boxID || rootTree.Path != plan.rootPath ||
		rootTree.HPath != plan.rootHPath {
		return false, errors.New("the document used to render the template has changed")
	}
	target.templateDocTreeRootSnapshot = rootTree
	box := Conf.Box(plan.boxID)
	if nil == box {
		return false, ErrBoxNotFound
	}
	for _, tree := range plan.trees {
		if nil == tree || nil == tree.Root || tree.ID != tree.Root.ID || tree.Box != plan.boxID || box.Exist(tree.Path) {
			return false, errors.New("template document tree plan contains an invalid document snapshot")
		}
	}

	for _, tree := range plan.trees {

View on GitHub (pinned to 8641553a1f)

Solutions

  1. Render the plan from the same document (rootID and notebook) that the transaction's parent operations modify
  2. Ensure the transaction contains at least one operation whose ID (or insert ParentID/PreviousID/NextID) equals plan.rootID in the matching box
  3. Send one plan per transaction and never share plan IDs across documents
  4. Re-render the plan if the user switched documents between rendering and applying

Example fix

// before
tx.DoOperations = operationsFor(docB) // docB != plan.rootID
tx.TemplateDocTreePlanID = planIDFrom(docA)
// after
tx.DoOperations = operationsFor(planRootDoc) // parent ops must target the plan's root document
tx.TemplateDocTreePlanID = planIDFrom(planRootDoc)
Defensive patterns

Strategy: validation

Validate before calling

for _, op := range append(tx.DoOperations, tx.UndoOperations...) { if op.ID != planRootID && op.ParentID != planRootID { abort: plan/transaction document mismatch } }

Try / catch

if err != nil && strings.Contains(err.Error(), "does not match the edited document") { re-render the plan for the current document and rebuild the transaction }

Prevention

When it happens

Trigger: Client renders a plan against document A but submits the transaction whose parent operations edit document B; a transaction batch that mixes documents; using a plan ID captured from another editor tab open on a different document.

Common situations: Two editor tabs open, template rendered in tab 1 but transaction sent from tab 2; a script that renders once and applies to several documents; copy-pasted integration code reusing a plan across boxes/notebooks.

Understand the failure class

Background: "Must be a positive integer", "Invalid value", "Unsupported": the invalid-argument-value error family, when a library rejects the value you pass — this error's family across 35 libraries.

Related errors


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