{"record":{"id":"d26baabc8d6371ac","repo":"siyuan-note/siyuan","slug":"left-document-version-is-required","errorCode":null,"errorMessage":"left document version is required","messagePattern":"left document version is required","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"kernel/apicontract/history_diff.go","lineNumber":52,"sourceCode":"type DocVersionDiffResult struct {\n\tLeft          *DocVersionDiffContent  `json:\"left\"`\n\tRight         *DocVersionDiffContent  `json:\"right\"`\n\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 == \"\" {","sourceCodeStart":34,"sourceCodeEnd":70,"githubUrl":"https://github.com/siyuan-note/siyuan/blob/9f775e8a12daef8255556097396f9b2739078892/kernel/apicontract/history_diff.go#L34-L70","documentation":"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.","triggerScenarios":"POSTing to /api/history/diffDocVersions with no `left` key, \"left\": null, a non-object left (string/number/array), or malformed JSON in left.","commonSituations":"Diff UI invoking the endpoint when only one history version is selected; clients double-encoding the version object as a string.","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"],"exampleFix":"// before\n{\"right\": {\"type\": \"id\", \"id\": \"20240101120000-abcdef1\"}}\n// after\n{\"left\": {\"type\": \"id\", \"id\": \"20240101110000-abcdef0\"}, \"right\": {\"type\": \"id\", \"id\": \"20240101120000-abcdef1\"}}","handlingStrategy":"validation","validationCode":"function isValidVersionRef(v) {\n  return v != null && typeof v === \"object\" && !Array.isArray(v) && typeof v.type === \"string\" && v.type.trim() !== \"\";\n}\nif (!isValidVersionRef(body.left)) throw new Error(\"left version ref required\");","typeGuard":"const isVersionRef = (v) => v !== null && typeof v === \"object\" && typeof v.type === \"string\";","tryCatchPattern":null,"preventionTips":["Resolve both history versions before opening the diff","Check that both selection slots in the UI are filled before invoking the endpoint"],"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"}