siyuan-note/siyuan · error

Field [keyIDs] is required

Error message

Field [keyIDs] is required

What it means

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.

Solutions

  1. Include keyIDs as a JSON array of field/view key IDs in the request body
  2. Check request.KeyIDsError (or the returned error) before processing the response
  3. If all keys are wanted, pass the complete list explicitly rather than omitting the field

Example fix

// before
fetchPost("/api/av/getAttributeViewKeysByID", {avID});
// after
fetchPost("/api/av/getAttributeViewKeysByID", {avID, keyIDs: ["custom-attr-1"]});
Defensive patterns

Strategy: validation

Validate before calling

function assertKeyIDs(payload) { if (!Array.isArray(payload.keyIDs)) throw new Error("Field [keyIDs] is required"); }

Type guard

const hasKeyIDs = (p) => Array.isArray(p?.keyIDs);

Try / catch

try { const res = await post("/api/av/getAttributeViewKeysByID", payload); if (res.keyIDsError) handle(res.keyIDsError); } catch (e) { /* ... */ }

Prevention

When it happens

Trigger: POST /api/av/getAttributeViewKeysByID without a 'keyIDs' member in the JSON body.

Common situations: Plugin code written against a payload shape without keyIDs, scripts fetching all keys by omitting the field, older API examples predating the keyIDs parameter.

Understand the failure class

Background: "missing required argument" and "the following required arguments were not provided": what required-argument errors mean and how to fix them — this error's family across 20 libraries.

Related errors


AI-assisted analysis of siyuan-note/siyuan@9f775e8a12 (2026-09-19). Data as JSON: /api/errors/68f7ed16133e7e52. Report an issue: GitHub.

Appendix: source

Thrown at kernel/apicontract/av_decode.go:80

}

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")

View on GitHub (pinned to 9f775e8a12)