siyuan-note/siyuan · error

encrypted document history root ID does not match its filena

Error message

encrypted document history root ID does not match its filename

What it means

GetDocHistoryContent reads a historical .sy snapshot and, when the source notebook is encrypted, verifies that the decrypted tree's root block ID matches the history filename (<rootID>.sy). If the decrypted document's root ID differs from the filename, the snapshot is inconsistent (renamed, corrupted, or wrongly decrypted) and the function aborts rather than serve content that cannot be traced back to the named document.

Source

Thrown at kernel/model/history.go:221

	} else if len(pathParts) >= 2 && IsEncryptedBox(pathParts[1]) {
		err = fmt.Errorf("encrypted notebook document history is plaintext [%s]", pathParts[1])
		return
	}
	isLargeDoc = 1024*1024*1 <= len(data)

	luteEngine := NewLute()
	if err = treenode.CheckSpecJSON(data); nil != err {
		return
	}
	historyTree, err := dataparser.ParseJSONWithoutFix(data, luteEngine.ParseOptions)
	if err != nil {
		logging.LogErrorf("parse tree from file [%s] failed: %s", historyPath, err)
		return
	}
	id = historyTree.Root.ID
	rootID = historyTree.Root.ID
	if ciphertext && rootID+".sy" != filepath.Base(historyPath) {
		return "", "", "", false, errors.New("encrypted document history root ID does not match its filename")
	}

	if !isLargeDoc {
		renderTree := &parse.Tree{Root: &ast.Node{Type: ast.NodeDocument}}
		keyword = strings.Join(strings.Split(keyword, " "), search.TermSep)
		keywords := search.SplitKeyword(keyword)

		var unlinks []*ast.Node
		ast.Walk(historyTree.Root, func(n *ast.Node, entering bool) ast.WalkStatus {
			if !entering {
				return ast.WalkContinue
			}

			// 数据历史浏览时忽略内容块折叠状态 https://github.com/siyuan-note/siyuan/issues/5778
			n.RemoveIALAttr("heading-fold")
			n.RemoveIALAttr("fold")

			if highlight && 0 < len(keywords) {

View on GitHub (pinned to 8641553a1f)

Solutions

  1. Verify the history file was not manually renamed: the basename must equal <rootID>.sy of the document inside
  2. Re-generate history for the document (edit and let the auto-history snapshot run) instead of copying old snapshots
  3. Confirm the notebook's DEK is the original one — decrypting with a wrong key yields a tree whose ID won't match
  4. Remove the inconsistent snapshot file if it is unrecoverable and rely on other history entries

Example fix

// before: renamed history file breaks lookup
mv data/history/20260910/boxID/oldid.sy data/history/20260910/boxID/newname.sy
// after: keep filename in sync with root ID
cp data/history/20260910/boxID/<rootID>.sy backup/ && rm data/history/20260910/boxID/newname.sy
Defensive patterns

Strategy: validation

Validate before calling

const base = historyPath.split("/").pop()
// before rolling forward to content rendering, confirm the snapshot belongs to the doc
const docRootId = docId // known document ID
if (!base || !base.startsWith(docRootId) || !base.endsWith(".sy")) throw new Error("history filename does not match document ID")

Type guard

function isConsistentHistoryPath(historyPath, rootId) {
  return typeof historyPath === "string" &&
    historyPath.endsWith(`/${rootId}.sy`)
}

Try / catch

try {
  const res = await fetchPost("/api/history/getDocHistoryContent", {historyPath})
} catch (e) {
  if (String(e.msg || e).includes("does not match its filename")) {
    // skip this snapshot; the file was renamed or corrupted
  }
}

Prevention

When it happens

Trigger: Calling getDocHistoryContent (kernel API history/getDocHistoryContent) for a history file under an encrypted notebook whose decrypted root.ID plus '.sy' does not equal filepath.Base(historyPath); e.g. a history file that was renamed, copied between documents, or whose ciphertext decrypts with the wrong/derived key producing a mismatched tree.

Common situations: Hand-editing or moving files inside data/history/; restoring history files from another workspace or notebook; DEK/key rotation leaving stale ciphertext; history snapshots taken before a document ID was regenerated.

Understand the failure class

Background: Checksum mismatch errors: "checksum verification failed", "digest mismatch", "expected vs actual checksum" — what they mean and how to fix them — this error's family across 41 libraries.

Related errors


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