siyuan-note/siyuan · error

document versions do not belong to the same document

Error message

document versions do not belong to the same document

What it means

DiffDocVersions loads both version references; if both sides resolved to non-empty root IDs that differ, the two versions cannot belong to the same document and the diff is refused with this error. Comparing versions of two different documents is not a defined operation.

Solutions

  1. Ensure both DocVersionRefs reference the same document's versions.
  2. Refresh the client's version list for the currently open document before diffing.
  3. If the document was deleted and recreated, diff against the old doc's history entries only (both sides from history), not the new current doc.
  4. Check sync history: a document ID change means old and new are different documents.

Example fix

// before
diff, err := model.DiffDocVersions(refOfDocA, refOfDocB)
// after
if rootIDOf(refOfDocA) != rootIDOf(refOfDocB) {
    return fmt.Errorf("cannot diff versions of different documents")
}
diff, err := model.DiffDocVersions(refOfDocA, refOfDocA2)
Defensive patterns

Strategy: validation

Validate before calling

// resolve both refs first and compare root IDs
type rooter interface{ RootID() string }
if a, b := rootIDOf(leftRef), rootIDOf(rightRef); a != "" && b != "" && a != b {
    return fmt.Errorf("refs point to different documents: %s vs %s", a, b)
}
diff, err := model.DiffDocVersions(leftRef, rightRef)

Try / catch

diff, err := model.DiffDocVersions(leftRef, rightRef)
if err != nil && strings.Contains(err.Error(), "do not belong to the same document") {
    return fmt.Errorf("refresh version list: selection mixed documents")
}

Prevention

When it happens

Trigger: DiffDocVersions(leftRef, rightRef) is called where left.rootID != right.rootID and both are non-empty - e.g. user selected two history entries of different docs, or a client passed a current-doc ref and a history/snapshot ref belonging to another document.

Common situations: Frontend diff UI state stale after the user switched documents; IDs mixed up in a custom script; a document was deleted and recreated (new root ID) and an old history ref is paired with the new current ref; sync replaced the document with different ID.

Understand the failure class

Background: "is not a compatible type" / "cannot merge" errors: when a value's type doesn't match what the library requires — this error's family across 65 libraries.

Related errors


AI-assisted analysis of siyuan-note/siyuan@9f775e8a12 (2026-09-19). Data as JSON: /api/errors/a7426a6148766793. Report an issue: GitHub.

Appendix: source

Thrown at kernel/model/history_diff.go:163

		return "", fmt.Errorf("unsupported document version type [%s]", ref.Type)
	}
}

// DiffDocVersions 比较同一文档的两个版本,并返回带临时差异标记的只读块 DOM。
func DiffDocVersions(leftRef, rightRef *DocVersionRef) (ret *DocVersionDiffResult, err error) {
	if (nil != leftRef && docVersionCurrent == leftRef.Type) || (nil != rightRef && docVersionCurrent == rightRef.Type) {
		FlushTxQueue()
	}
	left, err := loadDocVersion(leftRef)
	if err != nil {
		return nil, err
	}
	right, err := loadDocVersion(rightRef)
	if err != nil {
		return nil, err
	}
	if "" != left.rootID && "" != right.rootID && left.rootID != right.rootID {
		return nil, errors.New("document versions do not belong to the same document")
	}

	ret = &DocVersionDiffResult{
		Differences:   []*DocVersionDifference{},
		Large:         left.large || right.large,
		TitleModified: left.title != right.title,
	}
	if nil == left.tree || nil == right.tree {
		ret.Fallback = true
		ret.Message = docVersionFallbackMessage(left, right)
		ret.TitleModified = false
		ret.Left = renderFallbackDocVersion(left)
		ret.Right = renderFallbackDocVersion(right)
		return
	}
	if ret.TitleModified {
		ret.Differences = append(ret.Differences, &DocVersionDifference{
			ID:       left.tree.Root.ID,

View on GitHub (pinned to 9f775e8a12)