siyuan-note/siyuan · error
document version is empty
Error message
document version is empty
What it means
After the type dispatch, loadDocVersion sanity-checks the loaded version: it must produce a parseable tree with a Root, or raw content. If the loader returned an empty result (nil tree, no raw bytes, or tree without Root), this error signals the stored version is empty or unparseable - the version data itself is unusable.
Solutions
- Inspect the history/snapshot file referenced by the ref - if it is 0 bytes or truncated, discard that version and pick another.
- Restore the affected history data from sync/backup snapshot.
- Re-create the history entry by editing and re-saving the document (generates a fresh snapshot).
- Check kernel logs for parse errors just before this message to identify the corrupt source.
- Do not hand-edit files under data/history/; let the kernel manage them.
Example fix
// caller-side guard
loaded, err := loadHistoryDocVersion(ref.Path)
if err != nil {
logging.LogErrorf("skip unusable doc version [%s]: %v", ref.Path, err)
return nil, fmt.Errorf("history version [%s] is corrupt, choose another version", ref.Path)
} Defensive patterns
Strategy: try-catch
Validate before calling
info, err := os.Stat(historyFile)
if err != nil || info.Size() == 0 {
return fmt.Errorf("history version file %s is missing or empty; pick another version", historyFile)
} Try / catch
diff, err := model.DiffDocVersions(leftRef, rightRef)
if err != nil && strings.Contains(err.Error(), "document version is empty") {
return fmt.Errorf("a selected version is corrupt/empty; choose different versions or restore from backup")
} Prevention
- Never hand-edit data/history files
- Ensure disks are not full during history writes
- Restore corrupted history from sync/backup snapshots
- Regenerate history by re-saving the document
When it happens
Trigger: loadCurrentDocVersion / loadHistoryDocVersion / loadSnapshotDocVersion returned a loadedDocVersion with nil tree, empty raw, or tree.Root == nil - e.g. a zero-byte or truncated .sy history file, a corrupt snapshot entry, or a history record whose content failed to parse into a tree.
Common situations: History file truncated by disk-full during a previous write; snapshot corrupted after interrupted sync/backup restore; hand-edited or partially copied history directory; ancient format version the parser reads as empty.
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
- document versions do not belong to the same document
- current document ID is invalid
- document version is required
- export failed: empty content
- --left and --right are required
AI-assisted analysis of siyuan-note/siyuan@9f775e8a12 (2026-09-19).
Data as JSON: /api/errors/3ffb2db4207fdaae.
Report an issue: GitHub.
Appendix: source
Thrown at kernel/model/history_diff.go:270
}
switch ref.Type {
case docVersionCurrent:
if !ast.IsNodeIDPattern(ref.ID) {
return nil, errors.New("current document ID is invalid")
}
ret, err = loadCurrentDocVersion(ref.ID)
case docVersionHistory:
ret, err = loadHistoryDocVersion(ref.Path)
case docVersionSnapshot:
ret, err = loadSnapshotDocVersion(ref.ID)
default:
return nil, fmt.Errorf("unsupported document version type [%s]", ref.Type)
}
if err != nil {
return nil, err
}
if nil == ret || (nil == ret.tree && 0 == len(ret.raw)) || (nil != ret.tree && nil == ret.tree.Root) {
return nil, errors.New("document version is empty")
}
if nil != ret.tree && "" == ret.rootID {
ret.rootID = ret.tree.Root.ID
}
if nil != ret.tree && "" == ret.title {
ret.title = ret.tree.Root.IALAttr("title")
}
if "" == ret.title {
ret.title = ret.rootID
}
return
}
func loadCurrentDocVersion(id string) (ret *loadedDocVersion, err error) {
blockTree := treenode.GetBlockTree(id)
if nil == blockTree {
return nil, ErrTreeNotFound
}View on GitHub (pinned to 9f775e8a12)