{"record":{"id":"2d752817f04f3e9b","repo":"siyuan-note/siyuan","slug":"field-values-should-be-of-type-object","errorCode":null,"errorMessage":"Field [values]: should be of type [Object]","messagePattern":"Field \\[values\\]: should be of type \\[Object\\]","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"kernel/apicontract/storage.go","lineNumber":39,"sourceCode":"\t\tvar entries []json.RawMessage\n\t\tif json.Unmarshal(raw, &entries) != nil {\n\t\t\treturn request, errors.New(\"Field [rootIDs] should be of type [Array]\")\n\t\t}\n\t\tfor _, entry := range entries {\n\t\t\tvar id string\n\t\t\tif json.Unmarshal(entry, &id) == nil && id != \"\" {\n\t\t\t\trequest.RootIDs = append(request.RootIDs, id)\n\t\t\t}\n\t\t}\n\t\treturn\n\t}\n\tplain := PatchViewState\n\tPatchViewState.decodeRequest = func(reader io.Reader) (ViewStatePatchRequest, error) {\n\t\trequest, err := plain.Decode(reader)\n\t\tif err != nil {\n\t\t\tswitch {\n\t\t\tcase strings.HasPrefix(err.Error(), \"Field [values]\"):\n\t\t\t\terr = errors.New(\"Field [values]: should be of type [Object]\")\n\t\t\tcase strings.HasPrefix(err.Error(), \"Field [removeKeys]\"):\n\t\t\t\terr = errors.New(\"Field [removeKeys]: each element should be a non-empty String\")\n\t\t\t}\n\t\t}\n\t\treturn request, err\n\t}\n}\n\ntype RecentDocUpdateRequest struct {\n\tRootID string `json:\"rootID\" api:\"optional,nullable\"`\n}\ntype RecentDocsUpdateRequest struct {\n\tRootIDs []string `json:\"rootIDs\" api:\"optional,nullable\"`\n}\n\ntype StorageKeyRequest struct {\n\tKey string `json:\"key\" api:\"trim\"`\n}","sourceCodeStart":21,"sourceCodeEnd":57,"githubUrl":"https://github.com/siyuan-note/siyuan/blob/9f775e8a12daef8255556097396f9b2739078892/kernel/apicontract/storage.go#L21-L57","documentation":"This error is returned when decoding the request body for POST /api/storage/setViewState (the PatchViewState endpoint). The generic decoder detects that the `values` field failed to unmarshal into map[string]JSONValue, and this wrapper rewrites the message into a friendlier form. It means the JSON you sent has `values` as a non-object (e.g. a string, array, number, or boolean) instead of a JSON object of key/value pairs.","triggerScenarios":"Calling /api/storage/setViewState with `values` set to a scalar or array, e.g. {\"key\":\"local\",\"values\":\"oops\"} or {\"key\":\"local\",\"values\":[1,2]}; also when `values` has a wrong nested type the decoder reports a Field [values] prefix error which is rewritten here.","commonSituations":"Manually hand-crafting the curl payload for view-state persistence; an old client version sending the pre-patch flat format; a script serializing values with JSON.stringify applied twice so `values` becomes a string.","solutions":["Send `values` as a JSON object: {\"key\":\"<stateKey>\",\"values\":{\"someKey\":123}}","If you only want to delete entries, omit `values` (it is optional) and pass `removeKeys` as an array of non-empty strings","Validate the payload with JSON.parse/typeof checks before the HTTP call"],"exampleFix":"// before\n{\"key\":\"local\", \"values\":\"{\\\"width\\\":300}\"}\n// after\n{\"key\":\"local\", \"values\":{\"width\":300}}","handlingStrategy":"validation","validationCode":"function isViewStatePatchPayload(p){ return p && typeof p.key === 'string' && (p.values === undefined || (typeof p.values === 'object' && p.values !== null && !Array.isArray(p.values))); }","typeGuard":"const isRecord = (v) => typeof v === 'object' && v !== null && !Array.isArray(v);","tryCatchPattern":"try { const res = await fetchPost('/api/storage/setViewState', payload); if (res.code !== 0) console.error(res.msg); } catch (e) { /* network failure */ }","preventionTips":["Always build values with an object literal, never a pre-stringified JSON string","Remember values is optional — omit it when only removing keys","Unit-test the payload shape before hitting the kernel"],"tags":["json","validation","http-api","siyuan"],"backgroundTag":"type-mismatch","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"}