{"record":{"id":"68f7ed16133e7e52","repo":"siyuan-note/siyuan","slug":"field-keyids-is-required","errorCode":null,"errorMessage":"Field [keyIDs] is required","messagePattern":"Field \\[keyIDs\\] is required","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"kernel/apicontract/av_decode.go","lineNumber":80,"sourceCode":"}\n\nfunc init() {\n\tGetAttributeViewRowSort.decodeRequest = func(reader io.Reader) (request GetAttributeViewRowSortRequest, err error) {\n\t\terr = json.NewDecoder(reader).Decode(&request)\n\t\treturn request, err\n\t}\n\tGetAttributeViewKeysByID.decodeRequest = func(reader io.Reader) (request GetAttributeViewKeysByIDRequest, err error) {\n\t\tfields, err := blockRequestFields(reader, \"/api/av/getAttributeViewKeysByID\")\n\t\tif err != nil {\n\t\t\treturn request, err\n\t\t}\n\t\traw, present := fields[\"keyIDs\"]\n\t\tfields[\"keyIDs\"] = json.RawMessage(\"[]\")\n\t\tif err = decodeRequestFields(reflect.ValueOf(&request).Elem(), fields); err != nil {\n\t\t\treturn request, err\n\t\t}\n\t\tif !present {\n\t\t\trequest.KeyIDsError = fmt.Errorf(\"Field [keyIDs] is required\")\n\t\t} else if bytes.Equal(bytes.TrimSpace(raw), []byte(\"null\")) {\n\t\t\trequest.KeyIDsError = fmt.Errorf(\"Field [keyIDs] must not be null\")\n\t\t} else {\n\t\t\trequest.KeyIDsError = decodeRequestValue(raw, reflect.ValueOf(&request.KeyIDs).Elem())\n\t\t}\n\t\treturn request, nil\n\t}\n\tGetAttributeViewPasteRows.decodeRequest = func(reader io.Reader) (GetAttributeViewPasteRowsRequest, error) {\n\t\treturn avDecodeParsedRequest[GetAttributeViewPasteRowsRequest](reader, \"/api/av/getAttributeViewPasteRows\")\n\t}\n\tGetAttributeViewFieldViews.decodeRequest = func(reader io.Reader) (GetAttributeViewFieldViewsRequest, error) {\n\t\treturn avDecodeParsedRequest[GetAttributeViewFieldViewsRequest](reader, \"/api/av/getAttributeViewFieldViews\")\n\t}\n\tCreateAttributeViewItem.decodeRequest = func(reader io.Reader) (CreateAttributeViewItemRequest, error) {\n\t\treturn avDecodeParsedRequest[CreateAttributeViewItemRequest](reader, \"/api/av/createAttributeViewItem\")\n\t}\n\tCreateAttributeViewItemWithMarkdown.decodeRequest = func(reader io.Reader) (CreateAttributeViewItemWithMarkdownRequest, error) {\n\t\treturn avDecodeParsedRequest[CreateAttributeViewItemWithMarkdownRequest](reader, \"/api/av/createAttributeViewItemWithMarkdown\")","sourceCodeStart":62,"sourceCodeEnd":98,"githubUrl":"https://github.com/siyuan-note/siyuan/blob/9f775e8a12daef8255556097396f9b2739078892/kernel/apicontract/av_decode.go#L62-L98","documentation":"The getAttributeViewKeysByID endpoint decodes keyIDs leniently: the struct decode always succeeds (keyIDs defaults to []), but if the 'keyIDs' field is missing, the request carries KeyIDsError = 'Field [keyIDs] is required'. The endpoint can inspect this error and respond accordingly instead of failing the decode itself.","triggerScenarios":"POST /api/av/getAttributeViewKeysByID without a 'keyIDs' member in the JSON body.","commonSituations":"Plugin code written against a payload shape without keyIDs, scripts fetching all keys by omitting the field, older API examples predating the keyIDs parameter.","solutions":["Include keyIDs as a JSON array of field/view key IDs in the request body","Check request.KeyIDsError (or the returned error) before processing the response","If all keys are wanted, pass the complete list explicitly rather than omitting the field"],"exampleFix":"// before\nfetchPost(\"/api/av/getAttributeViewKeysByID\", {avID});\n// after\nfetchPost(\"/api/av/getAttributeViewKeysByID\", {avID, keyIDs: [\"custom-attr-1\"]});","handlingStrategy":"validation","validationCode":"function assertKeyIDs(payload) { if (!Array.isArray(payload.keyIDs)) throw new Error(\"Field [keyIDs] is required\"); }","typeGuard":"const hasKeyIDs = (p) => Array.isArray(p?.keyIDs);","tryCatchPattern":"try { const res = await post(\"/api/av/getAttributeViewKeysByID\", payload); if (res.keyIDsError) handle(res.keyIDsError); } catch (e) { /* ... */ }","preventionTips":["Always send keyIDs explicitly, even when listing all keys","Default null to [] before building the payload","Read the endpoint's KeyIDsError from the response when it uses lenient decoding"],"tags":["validation","api","attribute-view"],"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"}