siyuan-note/siyuan · error
Field [keyIDs] must not be null
Error message
Field [keyIDs] must not be null
What it means
Same lenient keyIDs decoding as the 'is required' case, but for an explicitly null value: when 'keyIDs' is present yet JSON null, GetAttributeViewKeysByIDRequest.KeyIDsError is set to 'Field [keyIDs] must not be null'. Null cannot be decoded into the key-ID string slice.
Solutions
- Replace null with an empty array [] if no specific keys are needed
- Default the variable before sending: keyIDs = keyIDs ?? []
- Handle the KeyIDsError surfaced by the endpoint response
Example fix
// before
fetchPost("/api/av/getAttributeViewKeysByID", {avID, keyIDs: null});
// after
fetchPost("/api/av/getAttributeViewKeysByID", {avID, keyIDs: keyIDs ?? []}); Defensive patterns
Strategy: validation
Validate before calling
payload.keyIDs = payload.keyIDs ?? [];
Type guard
const isStringArray = (v) => Array.isArray(v) && v.every((x) => typeof x === "string");
Try / catch
try { const res = await post("/api/av/getAttributeViewKeysByID", payload); if (res.keyIDsError) handle(res.keyIDsError); } catch (e) { /* ... */ } Prevention
- Avoid `keyIDs: maybeUndefined` shorthand; use explicit defaults
- Check for null after JSON.parse of stored settings
- Write a payload builder that guarantees array-typed fields
When it happens
Trigger: POST /api/av/getAttributeViewKeysByID with {"keyIDs": null}.
Common situations: Client code doing keyIDs: someVar where someVar is undefined/null, serializers emitting null for empty lists, template interpolation producing null.
Related errors
- Field [ ] must not be null
- AI editor action must not be empty
- block [ ] type is locked: expected , got
- block swap requires two non-document blocks
- Bookmark cannot be empty
AI-assisted analysis of siyuan-note/siyuan@9f775e8a12 (2026-09-19).
Data as JSON: /api/errors/4fea9ec958f5410a.
Report an issue: GitHub.
Appendix: source
Thrown at kernel/apicontract/av_decode.go:82
func init() {
GetAttributeViewRowSort.decodeRequest = func(reader io.Reader) (request GetAttributeViewRowSortRequest, err error) {
err = json.NewDecoder(reader).Decode(&request)
return request, err
}
GetAttributeViewKeysByID.decodeRequest = func(reader io.Reader) (request GetAttributeViewKeysByIDRequest, err error) {
fields, err := blockRequestFields(reader, "/api/av/getAttributeViewKeysByID")
if err != nil {
return request, err
}
raw, present := fields["keyIDs"]
fields["keyIDs"] = json.RawMessage("[]")
if err = decodeRequestFields(reflect.ValueOf(&request).Elem(), fields); err != nil {
return request, err
}
if !present {
request.KeyIDsError = fmt.Errorf("Field [keyIDs] is required")
} else if bytes.Equal(bytes.TrimSpace(raw), []byte("null")) {
request.KeyIDsError = fmt.Errorf("Field [keyIDs] must not be null")
} else {
request.KeyIDsError = decodeRequestValue(raw, reflect.ValueOf(&request.KeyIDs).Elem())
}
return request, nil
}
GetAttributeViewPasteRows.decodeRequest = func(reader io.Reader) (GetAttributeViewPasteRowsRequest, error) {
return avDecodeParsedRequest[GetAttributeViewPasteRowsRequest](reader, "/api/av/getAttributeViewPasteRows")
}
GetAttributeViewFieldViews.decodeRequest = func(reader io.Reader) (GetAttributeViewFieldViewsRequest, error) {
return avDecodeParsedRequest[GetAttributeViewFieldViewsRequest](reader, "/api/av/getAttributeViewFieldViews")
}
CreateAttributeViewItem.decodeRequest = func(reader io.Reader) (CreateAttributeViewItemRequest, error) {
return avDecodeParsedRequest[CreateAttributeViewItemRequest](reader, "/api/av/createAttributeViewItem")
}
CreateAttributeViewItemWithMarkdown.decodeRequest = func(reader io.Reader) (CreateAttributeViewItemWithMarkdownRequest, error) {
return avDecodeParsedRequest[CreateAttributeViewItemWithMarkdownRequest](reader, "/api/av/createAttributeViewItemWithMarkdown")
}
CreateAttributeViewItemDocs.decodeRequest = func(reader io.Reader) (CreateAttributeViewItemDocsRequest, error) {View on GitHub (pinned to 9f775e8a12)