siyuan-note/siyuan · error
Field [values]: should be of type [Object]
Error message
Field [values]: should be of type [Object]
What it means
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.
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
Example fix
// before
{"key":"local", "values":"{\"width\":300}"}
// after
{"key":"local", "values":{"width":300}} Defensive patterns
Strategy: validation
Validate before calling
function isViewStatePatchPayload(p){ return p && typeof p.key === 'string' && (p.values === undefined || (typeof p.values === 'object' && p.values !== null && !Array.isArray(p.values))); } Type guard
const isRecord = (v) => typeof v === 'object' && v !== null && !Array.isArray(v);
Try / catch
try { const res = await fetchPost('/api/storage/setViewState', payload); if (res.code !== 0) console.error(res.msg); } catch (e) { /* network failure */ } Prevention
- 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
When it happens
Trigger: 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.
Common situations: 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.
Understand the failure class
Background: Type mismatch errors: IllegalArgumentException, TypeError and type guards across 150 open-source libraries — this error's family across 150 libraries.
Related errors
- Field [removeKeys]: each element should be a non-empty…
- 106
- 199
- block operation context
- builtin color must not be null
AI-assisted analysis of siyuan-note/siyuan@9f775e8a12 (2026-09-19).
Data as JSON: /api/errors/2d752817f04f3e9b.
Report an issue: GitHub.
Appendix: source
Thrown at kernel/apicontract/storage.go:39
var entries []json.RawMessage
if json.Unmarshal(raw, &entries) != nil {
return request, errors.New("Field [rootIDs] should be of type [Array]")
}
for _, entry := range entries {
var id string
if json.Unmarshal(entry, &id) == nil && id != "" {
request.RootIDs = append(request.RootIDs, id)
}
}
return
}
plain := PatchViewState
PatchViewState.decodeRequest = func(reader io.Reader) (ViewStatePatchRequest, error) {
request, err := plain.Decode(reader)
if err != nil {
switch {
case strings.HasPrefix(err.Error(), "Field [values]"):
err = errors.New("Field [values]: should be of type [Object]")
case strings.HasPrefix(err.Error(), "Field [removeKeys]"):
err = errors.New("Field [removeKeys]: each element should be a non-empty String")
}
}
return request, err
}
}
type RecentDocUpdateRequest struct {
RootID string `json:"rootID" api:"optional,nullable"`
}
type RecentDocsUpdateRequest struct {
RootIDs []string `json:"rootIDs" api:"optional,nullable"`
}
type StorageKeyRequest struct {
Key string `json:"key" api:"trim"`
}View on GitHub (pinned to 9f775e8a12)