siyuan-note/siyuan · critical
encrypted .sy [ ]: base id [ ] != root id [ ]
Error message
encrypted .sy [%s]: base id [%s] != root id [%s]
What it means
For encrypted notebooks, fixTreeJSONData enforces fail-closed identity: the base-name ID of the .sy path must equal the root block ID of the decrypted content. A mismatch proves the ciphertext was swapped, the file renamed, or AAD authentication bypassed, so it is never silently auto-fixed (unencrypted trees get their ID reset instead).
Solutions
- Rename the .sy file back to the ID matching its root block ID (root.ID.sy).
- Restore the original encrypted file from backup or sync history; do not hand-edit ciphertext.
- If the mismatch is intentional, re-encrypt: export the document and re-import it into the encrypted notebook.
Example fix
// before: notebook/20240101-newname.sy decrypts to root.ID 20240101-oldname // after: mv 20240101-newname.sy 20240101-oldname.sy
Defensive patterns
Strategy: validation
Validate before calling
pathID := util.GetTreeID(p) // before writing into an encrypted notebook: ensure filename == root.ID + ".sy"
Type guard
func encryptedIdentityOK(pathID, rootID string) bool { return pathID == rootID } Try / catch
if _, err := filesys.LoadTreeWithFix(box, p, lute); err != nil && strings.Contains(err.Error(), "base id") {
// fail closed: do NOT auto-fix; restore the original encrypted file
} Prevention
- Never rename or swap .sy files inside encrypted notebooks
- Restore encrypted notebooks only from complete, consistent backups
- Re-import (export/import) documents instead of moving files between encrypted boxes
When it happens
Trigger: LoadTreeWithFix on an encrypted notebook where a .sy file was renamed, its ciphertext replaced with another document's, or where the decryption produced content whose Root.ID differs from the path-derived ID.
Common situations: Copying .sy files between notebooks and renaming them in an encrypted notebook, tampering attempts, or restoring encrypted files from a partial/mixed backup.
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
- cannot rebuild encrypted indexes
- duplicate encrypted document ID
- encrypted document is a symbolic link
- encrypted document root ID does not match filename
- encrypted notebook attribute view snapshot is plaintext
AI-assisted analysis of siyuan-note/siyuan@9f775e8a12 (2026-09-19).
Data as JSON: /api/errors/0387450a19b3c111.
Report an issue: GitHub.
Appendix: source
Thrown at kernel/filesys/tree.go:661
return
}
if treenode.UpgradeSpec(ret) {
needFix = true
}
// v3.5.1 https://github.com/siyuan-note/siyuan/pull/16657 引入的问题,属性值未转义
// v3.5.2 https://github.com/siyuan-note/siyuan/issues/16686 进行了修复,并加了订正逻辑 https://github.com/siyuan-note/siyuan/pull/16712
// https://github.com/siyuan-note/siyuan/security/advisories/GHSA-ff66-236v-p4fg XSS 漏洞:"title": "&\" onmouseenter=\"require('child_process').exec('calc')"
if escapeAttributeValues(ret) {
needFix = true
}
if pathID := util.GetTreeID(p); pathID != ret.Root.ID {
if encrypted {
// 加密 .sy:基名 ID(pathID)必须与解密后的根块 ID 一致。不一致说明密文被替换、
// 文件名被篡改或 AAD 认证被绕过,不得静默修正——fail-closed,符合加密笔记本威胁模型。
err = fmt.Errorf("encrypted .sy [%s]: base id [%s] != root id [%s]", p, pathID, ret.Root.ID)
logging.LogErrorf("%s", err)
return
}
needFix = true
logging.LogInfof("reset tree id from [%s] to [%s]", ret.Root.ID, pathID)
ret.Root.ID = pathID
ret.ID = pathID
ret.Root.SetIALAttr("id", ret.ID)
}
if treenode.FixInvalidListChildren(ret.Root) {
needFix = true
}
if treenode.NormalizeTabs(ret.Root) {
needFix = true
}
if !needFix {
return jsonData, false, nilView on GitHub (pinned to 9f775e8a12)