siyuan-note/siyuan · error
left document version is required
Error message
left document version is required
What it means
The /api/history/diffDocVersions decoder requires a `left` field containing a document version reference object. It unmarshals fields["left"] into a map; if unmarshaling fails or the result is nil (missing, null, or non-object), it returns 'left document version is required'. Both left and right sides are mandatory for a diff.
Solutions
- Send "left" as an object like {"type": "id", "id": "<block-id>", "path": "<history-path>"}
- Ensure left is a JSON object, not a quoted string
- Check both left and right are present — the right side is validated next with a parallel message
Example fix
// before
{"right": {"type": "id", "id": "20240101120000-abcdef1"}}
// after
{"left": {"type": "id", "id": "20240101110000-abcdef0"}, "right": {"type": "id", "id": "20240101120000-abcdef1"}} Defensive patterns
Strategy: validation
Validate before calling
function isValidVersionRef(v) {
return v != null && typeof v === "object" && !Array.isArray(v) && typeof v.type === "string" && v.type.trim() !== "";
}
if (!isValidVersionRef(body.left)) throw new Error("left version ref required"); Type guard
const isVersionRef = (v) => v !== null && typeof v === "object" && typeof v.type === "string";
Prevention
- Resolve both history versions before opening the diff
- Check that both selection slots in the UI are filled before invoking the endpoint
When it happens
Trigger: POSTing to /api/history/diffDocVersions with no `left` key, "left": null, a non-object left (string/number/array), or malformed JSON in left.
Common situations: Diff UI invoking the endpoint when only one history version is selected; clients double-encoding the version object as a string.
Understand the failure class
Background: "missing required argument" and "the following required arguments were not provided": what required-argument errors mean and how to fix them — this error's family across 20 libraries.
Related errors
- right document version is required
- Field [conf] is required
- Field [id] should be of type [String]
- Field [notebook] is required
- Field [ ] is required
AI-assisted analysis of siyuan-note/siyuan@9f775e8a12 (2026-09-19).
Data as JSON: /api/errors/d26baabc8d6371ac.
Report an issue: GitHub.
Appendix: source
Thrown at kernel/apicontract/history_diff.go:52
type DocVersionDiffResult struct {
Left *DocVersionDiffContent `json:"left"`
Right *DocVersionDiffContent `json:"right"`
Differences []*DocVersionDifference `json:"differences"`
Large bool `json:"large"`
Fallback bool `json:"fallback"`
Message string `json:"message"`
TitleModified bool `json:"titleModified"`
}
func init() {
DiffDocVersions.decodeRequest = func(reader io.Reader) (request DiffDocVersionsRequest, err error) {
fields, err := blockRequestFields(reader, "/api/history/diffDocVersions")
if err != nil {
return request, err
}
var left, right map[string]json.RawMessage
if json.Unmarshal(fields["left"], &left) != nil || left == nil {
return request, fmt.Errorf("left document version is required")
}
if json.Unmarshal(fields["right"], &right) != nil || right == nil {
return request, fmt.Errorf("right document version is required")
}
if request.Left, err = decodeDocVersionRef(left); err != nil {
return request, err
}
request.Right, err = decodeDocVersionRef(right)
return request, err
}
}
func decodeDocVersionRef(fields map[string]json.RawMessage) (request DocVersionRef, err error) {
if request.Type, err = legacyField[string](fields, "type", "String", true); err != nil {
return request, err
}
request.Type = strings.TrimSpace(request.Type)
if request.Type == "" {View on GitHub (pinned to 9f775e8a12)