siyuan-note/siyuan · error
document version is required
Error message
document version is required
What it means
Returned by ResolveDocVersionBoxID (history_diff.go:117) when the supplied *DocVersionRef is nil. ResolveDocVersionBoxID walks the ref to find which encrypted notebook a version belongs to, so a nil ref has no type/ID/path to inspect. This is the first guard before the type switch and exists to fail fast on missing input.
Source
Thrown at kernel/model/history_diff.go:117
signature string
}
type docTextSegment struct {
node *ast.Node
start int
end int
storedRuns []string
signature string
}
type docDiffLCSBudget struct {
remaining int
}
// ResolveDocVersionBoxID 返回文档版本引用中明确记录的加密笔记本 ID。
func ResolveDocVersionBoxID(ref *DocVersionRef) (string, error) {
if ref == nil {
return "", errors.New("document version is required")
}
switch ref.Type {
case docVersionCurrent:
if !ast.IsNodeIDPattern(ref.ID) {
return "", errors.New("current document ID is invalid")
}
blockTree := treenode.GetBlockTree(ref.ID)
if blockTree == nil {
return "", ErrTreeNotFound
}
if IsEncryptedBox(blockTree.BoxID) {
return blockTree.BoxID, nil
}
return "", nil
case docVersionHistory:
absPath, err := validateHistoryPath(ref.Path)
if err != nil {
return "", errView on GitHub (pinned to 251596fc0d)
Solutions
- Ensure the caller always constructs a non-nil DocVersionRef before invoking ResolveDocVersionBoxID or DiffDocVersions.
- At the API boundary, reject nil refs with util.ParseJsonArgs/BindJsonArg so the user gets a clear "X document version is required" message before reaching model code (see api/history.go:200-203 for the right-side example).
- Default to an empty struct (&DocVersionRef{}) only if downstream code tolerates an empty Type; otherwise surface the missing-field error to the user.
Example fix
// before
boxID, err := ResolveDocVersionBoxID(ref) // ref may be nil
// after
if ref == nil {
return "", errors.New("document version is required")
}
boxID, err := ResolveDocVersionBoxID(ref) Defensive patterns
Strategy: validation
Validate before calling
if ref == nil {
return "", errors.New("document version is required")
}
return ResolveDocVersionBoxID(ref) Type guard
// validDocVersionRef is a non-nil ref with a known type.
func validDocVersionRef(r *DocVersionRef) bool {
if r == nil { return false }
switch r.Type {
case docVersionCurrent, docVersionHistory, docVersionSnapshot:
return true
}
return false
} Prevention
- At the API boundary, require the "left"/"right" JSON objects so nil never reaches model code.
- Default-construct refs (&DocVersionRef{}) only when downstream tolerates an empty Type.
- Unit-test ResolveDocVersionBoxID with nil to confirm it fails fast.
When it happens
Trigger: POST /api/history/diffDocVersions or /api/history/rollbackDocHistory invoked with a missing or null "left"/"right" object that deserializes to a nil pointer; a Go caller passing nil instead of an empty DocVersionRef{}.
Common situations: Frontend sends {"left": null, "right": {...}}; a plugin/MCP tool omits the version object; refactoring that introduces an optional pointer without a default.
Related errors
- current document ID is invalid
- task list item marker length should be 1
- task list item marker can not be [ or ]
- custom emoji file is too large
- custom emoji file must not be empty
AI-assisted analysis of siyuan-note/siyuan@251596fc0d (2026-08-12).
Data as JSON: /api/errors/fa13efa7f8cadde5.
Report an issue: GitHub.