{"record":{"id":"c7f3fa6e85fe6f75","repo":"siyuan-note/siyuan","slug":"right-document-version-is-required","errorCode":null,"errorMessage":"right document version is required","messagePattern":"right document version is required","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"kernel/apicontract/history_diff.go","lineNumber":55,"sourceCode":"\tDifferences   []*DocVersionDifference `json:\"differences\"`\n\tLarge         bool                    `json:\"large\"`\n\tFallback      bool                    `json:\"fallback\"`\n\tMessage       string                  `json:\"message\"`\n\tTitleModified bool                    `json:\"titleModified\"`\n}\n\nfunc init() {\n\tDiffDocVersions.decodeRequest = func(reader io.Reader) (request DiffDocVersionsRequest, err error) {\n\t\tfields, err := blockRequestFields(reader, \"/api/history/diffDocVersions\")\n\t\tif err != nil {\n\t\t\treturn request, err\n\t\t}\n\t\tvar left, right map[string]json.RawMessage\n\t\tif json.Unmarshal(fields[\"left\"], &left) != nil || left == nil {\n\t\t\treturn request, fmt.Errorf(\"left document version is required\")\n\t\t}\n\t\tif json.Unmarshal(fields[\"right\"], &right) != nil || right == nil {\n\t\t\treturn request, fmt.Errorf(\"right document version is required\")\n\t\t}\n\t\tif request.Left, err = decodeDocVersionRef(left); err != nil {\n\t\t\treturn request, err\n\t\t}\n\t\trequest.Right, err = decodeDocVersionRef(right)\n\t\treturn request, err\n\t}\n}\n\nfunc decodeDocVersionRef(fields map[string]json.RawMessage) (request DocVersionRef, err error) {\n\tif request.Type, err = legacyField[string](fields, \"type\", \"String\", true); err != nil {\n\t\treturn request, err\n\t}\n\trequest.Type = strings.TrimSpace(request.Type)\n\tif request.Type == \"\" {\n\t\treturn request, fmt.Errorf(\"Field [type] must not be empty\")\n\t}\n\tif request.ID, err = legacyField[string](fields, \"id\", \"String\", false); err != nil {","sourceCodeStart":37,"sourceCodeEnd":73,"githubUrl":"https://github.com/siyuan-note/siyuan/blob/9f775e8a12daef8255556097396f9b2739078892/kernel/apicontract/history_diff.go#L37-L73","documentation":"Symmetric to the left-side check, the diffDocVersions decoder requires a `right` field holding a document version reference object. Unmarshal failure or a nil result (absent, null, or non-object value) produces 'right document version is required'.","triggerScenarios":"POSTing to /api/history/diffDocVersions with only `left` set, \"right\": null, or right as a non-object value.","commonSituations":"Selecting 'compare with previous' where the right version failed to resolve and the client sent null; partial request construction.","solutions":["Send \"right\" as a version reference object alongside left","Resolve the second history version before invoking the diff endpoint","Verify the payload with both keys: {\"left\": {...}, \"right\": {...}}"],"exampleFix":"// before\n{\"left\": {\"type\": \"id\", \"id\": \"20240101110000-abcdef0\"}}\n// after\n{\"left\": {\"type\": \"id\", \"id\": \"20240101110000-abcdef0\"}, \"right\": {\"type\": \"id\", \"id\": \"20240101120000-abcdef1\"}}","handlingStrategy":"validation","validationCode":"if (!isValidVersionRef(body.right)) throw new Error(\"right version ref required\");","typeGuard":"const isVersionRef = (v) => v !== null && typeof v === \"object\" && typeof v.type === \"string\";","tryCatchPattern":null,"preventionTips":["Validate both left and right together in one guard before the API call","Handle single-selection UI state by disabling the compare action"],"tags":["api","history","validation","missing-field"],"backgroundTag":"missing-required-argument","analyzedSha":"9f775e8a12daef8255556097396f9b2739078892","analyzedAt":"2026-09-19T03:17:15.984Z","contentChangedAt":"2026-09-19T03:17:15.984Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}