siyuan-note/siyuan · critical
encrypted .sy [%s]: base id [%s] != root id [%s]
Error message
encrypted .sy [%s]: base id [%s] != root id [%s]
What it means
Returned by `fixTreeJSONData` on encrypted notebooks when the ID parsed from the filename (`util.GetTreeID(p)`) does not equal the root block ID found inside the decrypted content. SiYuan treats this as a fail-closed integrity violation: a mismatch implies the ciphertext was replaced, the file was renamed, or AAD authentication was bypassed, so it refuses to silently rewrite the ID. Non-encrypted trees auto-fix the mismatch; encrypted trees do not.
Source
Thrown at kernel/filesys/tree.go:572
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 !needFix {
return jsonData, false, nil
}
renderer := render.NewJSONRenderer(ret, luteEngine.RenderOptions, luteEngine.ParseOptions)
data = renderer.Render()
if !util.UseSingleLineSave {View on GitHub (pinned to 251596fc0d)
Solutions
- Do not rename or move encrypted `.sy` files by hand; use SiYuan's own move/rename so IDs stay consistent.
- Restore the affected document from an encrypted history snapshot taken before the mismatch.
- If the mismatch is from a known migration bug, re-encrypt or re-save the document through the kernel so filename and root ID realign.
Defensive patterns
Strategy: try-catch
Validate before calling
// For encrypted trees, verify filename-vs-rootID alignment before deeper processing:
if pathID := util.GetTreeID(p); encrypted && pathID != tree.Root.ID {
return fmt.Errorf("encrypted .sy [%s]: base id [%s] != root id [%s]", p, pathID, tree.Root.ID)
} Try / catch
tree, err := filesys.LoadTree(box, p, lute)
if err != nil && strings.Contains(err.Error(), "base id") {
// integrity violation in encrypted box: do NOT auto-fix; restore from encrypted history
return err
} Prevention
- Never rename or copy encrypted .sy files outside the kernel.
- Resolve sync conflicts via the kernel's merge UI, not by file copy.
- Treat this error as a security signal; audit for tampering.
When it happens
Trigger: Renaming an encrypted `.sy` file outside SiYuan; copying ciphertext from one document into another file; a tampered or corrupted decrypt that produced a different root ID; an AAD-rotation bug. The error fires only when `encrypted == true`.
Common situations: Manual file operations inside an encrypted notebook's data dir; a sync conflict resolved by file copy; an attempt to defeat the binding between filename and content in an encrypted box.
Related errors
- encrypted blocktree db not opened for box %s
- encrypted notebook is locked, please unlock it first
- refuse to write decrypted asset inside workspace
- source is not an encrypted asset
- CLI does not support encrypted notebook [%s]
AI-assisted analysis of siyuan-note/siyuan@251596fc0d (2026-08-12).
Data as JSON: /api/errors/0387450a19b3c111.
Report an issue: GitHub.