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

  1. Inspect the history/snapshot file referenced by the ref - if it is 0 bytes or truncated, discard that version and pick another.
  2. Restore the affected history data from sync/backup snapshot.
  3. Re-create the history entry by editing and re-saving the document (generates a fresh snapshot).
  4. Check kernel logs for parse errors just before this message to identify the corrupt source.
  5. 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

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


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)