siyuan-note/siyuan · error
parse document history failed
Error message
parse document history failed
What it means
A defensive check right after parsing: if loadTreeByData0 returns no error but also a nil tree, the snapshot contains no usable document tree. The kernel raises this distinct message so callers get a clear failure instead of a nil-pointer panic later in the rollback path.
Source
Thrown at kernel/model/history.go:367
return
}
var decErr error
// 历史路径格式:<historyDir>/<datePrefix>/<boxID>/<relativePath>
// 用原始 boxID 解密(getRollbackBox 可能创建了新 box,密文仍属于原加密 box)
filePath := parts[2]
srcData, decErr = DecryptFile(origBoxID, filePath, dek, srcData)
if decErr != nil {
logging.LogErrorf("decrypt history [%s] failed: %s", srcPath, decErr)
err = decErr
return
}
}
tree, parseErr := loadTreeByData0(srcData)
if parseErr != nil {
return fmt.Errorf("parse document history failed: %w", parseErr)
}
if tree == nil {
return errors.New("parse document history failed")
}
if encrypted && tree.Root.ID+".sy" != filepath.Base(historyPath) {
return errors.New("encrypted document history root ID does not match its filename")
}
if nil != tree {
historyDir := filepath.Join(util.HistoryDir, parts[0])
avNodes := tree.Root.ChildrenByType(ast.NodeAttributeView)
for _, avNode := range avNodes {
srcAvPath := filepath.Join(historyDir, "storage", "av", avNode.AttributeViewID+".json")
// 加密笔记本的 AV 定义在笔记本级目录
destAvPath := filepath.Join(util.DataDir, "storage", "av", avNode.AttributeViewID+".json")
if IsEncryptedBox(boxID) {
// 历史目录里 AV 也可能在 boxID 子目录下
boxSrcAvPath := filepath.Join(historyDir, boxID, "storage", "av", avNode.AttributeViewID+".json")
if !gulu.File.IsExist(boxSrcAvPath) {
return fmt.Errorf("encrypted attribute view history is missing notebook context [%s]", avNode.AttributeViewID)
}View on GitHub (pinned to 8641553a1f)
Solutions
- Check the history file is non-empty and contains a document node; delete empty snapshots
- Roll back to a different history entry for the same document
- Regenerate history by editing and re-saving the document, then use the new snapshot
Example fix
// before
fetchPost("/api/history/rollbackDocHistory", {historyPath: emptySnapshotPath})
// after: skip empty snapshots when choosing an entry
const entries = historyList.filter(e => e.size > 0)
await fetchPost("/api/history/rollbackDocHistory", {historyPath: entries[0].path}) Defensive patterns
Strategy: validation
Validate before calling
const raw = await fetchPost("/api/file/getFile", {path: historyPath})
if (!raw || !raw.trim()) throw new Error("empty history snapshot, choose another entry") Type guard
function isNonEmptySnapshot(data) {
return typeof data === "string" && data.trim().length > 0
} Try / catch
try {
await fetchPost("/api/history/rollbackDocHistory", {historyPath})
} catch (e) {
if (String(e.msg || e) === "parse document history failed") {
// fall back to the next non-empty history entry
}
} Prevention
- Filter history entries by size > 0 before offering rollback
- Delete empty snapshots produced by interrupted writes
- Verify snapshots after crash recovery
When it happens
Trigger: rollbackDocHistory loads a history snapshot whose parsed result is nil — e.g. an empty file (0 bytes) that parses without error, or a loader edge case returning (nil, nil) for degenerate input.
Common situations: Zero-byte or whitespace-only history .sy files created by interrupted writes; snapshots of documents that were empty at snapshot time in a format the loader cannot represent; stale history entries left after a failed indexing run.
Understand the failure class
Background: "must not be empty", "cannot be empty" — required-field validation errors across open-source libraries — this error's family across 41 libraries.
Related errors
- parse document history failed: %w
- read history dir failed: %w
- parse encrypted notebook history conf [%s] failed: %w
- check encrypted notebook history failed: %w
- invalid historical notebook encryption key
AI-assisted analysis of siyuan-note/siyuan@8641553a1f (2026-09-11).
Data as JSON: /api/errors/80d1f877321faa96.
Report an issue: GitHub.