{"record":{"id":"8655403d97ce2b90","repo":"siyuan-note/siyuan","slug":"field-s-is-required","errorCode":null,"errorMessage":"Field [%s] is required","messagePattern":"Field \\[(.+?)\\] is required","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"kernel/apicontract/av_decode.go","lineNumber":22,"sourceCode":"\t\"bytes\"\n\t\"encoding/json\"\n\t\"fmt\"\n\t\"io\"\n\t\"reflect\"\n\t\"strings\"\n)\n\n// avDecodeBoundFields 仅对原本经过 JSON 结构体绑定的字段保留大小写匹配和数字归一化。\nfunc avDecodeBoundFields[Request any](reader io.Reader, path string, boundFields map[string]string, ignoredBools []string) (request Request, err error) {\n\tfields, err := blockRequestFields(reader, path)\n\tif err != nil {\n\t\treturn request, err\n\t}\n\toriginal := map[string]json.RawMessage{}\n\tfor name, placeholder := range boundFields {\n\t\traw, present := fields[name]\n\t\tif !present {\n\t\t\treturn request, fmt.Errorf(\"Field [%s] is required\", name)\n\t\t}\n\t\tif bytes.Equal(bytes.TrimSpace(raw), []byte(\"null\")) {\n\t\t\treturn request, fmt.Errorf(\"Field [%s] must not be null\", name)\n\t\t}\n\t\toriginal[name] = raw\n\t\tfields[name] = json.RawMessage(placeholder)\n\t}\n\tfor _, name := range ignoredBools {\n\t\toriginal[name] = fields[name]\n\t\tdelete(fields, name)\n\t}\n\tvalue := reflect.ValueOf(&request).Elem()\n\tif err = decodeRequestFields(value, fields); err != nil {\n\t\treturn request, err\n\t}\n\tfor i := 0; i < value.NumField(); i++ {\n\t\tfield := value.Type().Field(i)\n\t\tname := field.Tag.Get(\"json\")","sourceCodeStart":4,"sourceCodeEnd":40,"githubUrl":"https://github.com/siyuan-note/siyuan/blob/9f775e8a12daef8255556097396f9b2739078892/kernel/apicontract/av_decode.go#L4-L40","documentation":"avDecodeBoundFields handles attribute-view endpoints whose structurally complex fields are bound to placeholders during generic decoding, then re-decoded individually. Every name listed in boundFields must be present in the request; a missing field aborts decoding with 'Field [<name>] is required'.","triggerScenarios":"Calls to endpoints like /api/av/setAttrViewGroup (group), /api/av/setAttrViewFilters and setAttrViewSorts (data), appendAttributeViewDetachedBlocksWithValues (blocksValues), setAttributeViewBlockAttr (value), batchSetAttributeViewBlockAttrs (values) where the named field is omitted from the JSON body.","commonSituations":"Third-party plugin/API scripts migrating between SiYuan API versions with changed payload shapes, partial request objects built conditionally, typos in field names (e.g. 'value' vs 'values').","solutions":["Add the required field with its proper JSON value (object for value/group, array for data/values/blocksValues)","Check the endpoint's contract in docs/API-CONTRACTS.md for the exact required field name","Fix field-name typos in the client payload"],"exampleFix":"// before\nfetchPost(\"/api/av/setAttrViewFilters\", {avID: \"20240101\"});\n// after\nfetchPost(\"/api/av/setAttrViewFilters\", {avID: \"20240101\", data: []});","handlingStrategy":"validation","validationCode":"const REQUIRED = {setAttrViewGroup:[\"group\"],setAttrViewFilters:[\"data\"],setAttrViewSorts:[\"data\"],appendAttributeViewDetachedBlocksWithValues:[\"blocksValues\"],setAttributeViewBlockAttr:[\"value\"],batchSetAttributeViewBlockAttrs:[\"values\"]};\nfunction assertBound(endpoint, payload) { for (const f of REQUIRED[endpoint] ?? []) if (!(f in payload)) throw new Error(`Field [${f}] is required`); }","typeGuard":"const hasField = (obj, name) => obj != null && Object.prototype.hasOwnProperty.call(obj, name);","tryCatchPattern":"try { await post(avEndpoint, payload); } catch (e) { if (/is required/.test(e.message)) { console.error(\"missing field:\", e.message); } else throw e; }","preventionTips":["Consult docs/API-CONTRACTS.md for each av endpoint's required fields","Initialize container fields to [] or {} rather than conditionally omitting them","Add client-side payload schema tests for attribute-view calls"],"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"}