{"record":{"id":"502c7108bdd78893","repo":"siyuan-note/siyuan","slug":"paths-is-required","errorCode":null,"errorMessage":"[paths] is required","messagePattern":"\\[paths\\] is required","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"kernel/apicontract/asset.go","lineNumber":158,"sourceCode":"\t\tfields, err := blockRequestFields(reader, \"/api/asset/insertLocalAssets\")\n\t\tif err != nil {\n\t\t\treturn request, err\n\t\t}\n\t\tfromHTMLPaste := fields[\"fromHTMLPaste\"]\n\t\tdelete(fields, \"fromHTMLPaste\")\n\t\tif err = decodeRequestFields(reflect.ValueOf(&request).Elem(), fields); err != nil {\n\t\t\treturn request, err\n\t\t}\n\t\t_ = json.Unmarshal(fromHTMLPaste, &request.FromHTMLPaste)\n\t\treturn request, nil\n\t}\n\tAssetUploadCloudByAssetsPaths.decodeRequest = func(reader io.Reader) (request AssetPathsCloudUploadRequest, err error) {\n\t\tfields, err := blockRequestFields(reader, \"/api/asset/uploadCloudByAssetsPaths\")\n\t\tif err != nil {\n\t\t\treturn request, err\n\t\t}\n\t\tif len(fields[\"paths\"]) == 0 || string(fields[\"paths\"]) == \"null\" {\n\t\t\treturn request, errors.New(\"[paths] is required\")\n\t\t}\n\t\terr = decodeRequestFields(reflect.ValueOf(&request).Elem(), fields)\n\t\treturn request, err\n\t}\n}\n","sourceCodeStart":140,"sourceCodeEnd":164,"githubUrl":"https://github.com/siyuan-note/siyuan/blob/9f775e8a12daef8255556097396f9b2739078892/kernel/apicontract/asset.go#L140-L164","documentation":"The asset cloud-upload-by-paths endpoint requires a 'paths' array in the request. blockRequestFields decodes the body into fields, and if 'paths' is absent or the literal JSON null, the decoder returns '[paths] is required'. The request is rejected before any further field decoding.","triggerScenarios":"POST /api/asset/uploadCloudByAssetsPaths with body missing 'paths', or {\"paths\": null}, or not valid JSON containing paths.","commonSituations":"Scripts that build the payload conditionally and skip paths when a list is empty/unset, older client versions using a different payload shape, copy-pasted curl commands without the field.","solutions":["Include 'paths' as a JSON array of asset paths in the request body","Guard client-side: if the paths list is empty, skip the API call instead of sending an empty/absent field","Verify the body is valid JSON (Content-Type: application/json) so the field decoder sees paths"],"exampleFix":"// before\nfetchPost(\"/api/asset/uploadCloudByAssetsPaths\", {});\n// after\nfetchPost(\"/api/asset/uploadCloudByAssetsPaths\", {paths: [\"assets/foo.png\"]});","handlingStrategy":"validation","validationCode":"function assertPaths(payload) { if (!Array.isArray(payload.paths) || payload.paths.length === 0) throw new Error(\"[paths] is required\"); }","typeGuard":"const hasPaths = (p) => p != null && Array.isArray(p.paths) && p.paths.length > 0;","tryCatchPattern":"try { await post(\"/api/asset/uploadCloudByAssetsPaths\", payload); } catch (e) { if (/\\[paths\\] is required/.test(e.message)) { /* abort: nothing to upload */ } else throw e; }","preventionTips":["Skip the API call entirely when the path list is empty","Always build the payload from an explicitly initialized array","Validate JSON bodies with the API contract schema before sending"],"tags":["validation","api","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"}