{"record":{"id":"e3312b74e9bb6e5d","repo":"siyuan-note/siyuan","slug":"field-s-should-be-of-type-array","errorCode":null,"errorMessage":"Field [%s] should be of type [Array]","messagePattern":"Field \\[(.+?)\\] should be of type \\[Array\\]","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"kernel/apicontract/block_remaining.go","lineNumber":89,"sourceCode":"\tif raw, present := fields[\"scope\"]; present {\n\t\tif bytes.Equal(raw, []byte(\"null\")) || json.Unmarshal(raw, &request.Scope) != nil {\n\t\t\treturn request, errors.New(\"Field [scope] should be of type [String]\")\n\t\t}\n\t}\n\tif strings.TrimSpace(request.Scope) == \"\" {\n\t\trequest.Scope = \"blocks\"\n\t}\n\treadArray := func(key string, required, nonempty bool) ([]string, error) {\n\t\traw, present := fields[key]\n\t\tif !present && !required {\n\t\t\treturn nil, nil\n\t\t}\n\t\tif !present || bytes.Equal(raw, []byte(\"null\")) {\n\t\t\treturn nil, fmt.Errorf(\"Field [%s] is required\", key)\n\t\t}\n\t\tvar entries []json.RawMessage\n\t\tif json.Unmarshal(raw, &entries) != nil {\n\t\t\treturn nil, fmt.Errorf(\"Field [%s] should be of type [Array]\", key)\n\t\t}\n\t\tif nonempty && len(entries) == 0 {\n\t\t\treturn nil, fmt.Errorf(\"Field [%s] must not be empty\", key)\n\t\t}\n\t\tvar values []string\n\t\tseen := map[string]bool{}\n\t\tfor _, entry := range entries {\n\t\t\tvar value string\n\t\t\tif json.Unmarshal(entry, &value) != nil || strings.TrimSpace(value) == \"\" {\n\t\t\t\treturn nil, fmt.Errorf(\"Field [%s] should contain non-empty strings\", key)\n\t\t\t}\n\t\t\tif !seen[value] {\n\t\t\t\tvalues = append(values, value)\n\t\t\t\tseen[value] = true\n\t\t\t}\n\t\t}\n\t\treturn values, nil\n\t}","sourceCodeStart":71,"sourceCodeEnd":107,"githubUrl":"https://github.com/siyuan-note/siyuan/blob/9f775e8a12daef8255556097396f9b2739078892/kernel/apicontract/block_remaining.go#L71-L107","documentation":"The SiYuan kernel validates fields of the /api/block/checkBlockRef request body individually. When a declared array field (ids, exactIDs, deletedIDs, or paths) is present but its JSON value fails to unmarshal into a JSON array, the kernel rejects the request with this error. It means the field's value has the wrong JSON type (e.g. a string, number, or object) where an array is required.","triggerScenarios":"POST /api/block/checkBlockRef with scope \"blocks\" and ids given as a single string like \"ids\":\"20240101120000-abcdefg\" instead of [\"20240101120000-abcdefg\"]; scope \"documents\" with paths as a string instead of an array; or any of exactIDs/deletedIDs passed as a non-array JSON value.","commonSituations":"Wrapping a single block ID without array brackets when scripting the API; older plugin code written against a loose client that silently coerced scalars to arrays; building the payload with template string interpolation that drops the brackets; JSON serialization sending an object or quoted CSV string.","solutions":["Wrap the value in JSON array brackets: \"ids\": [\"<block-id>\"]","Ensure the client serializes the field as an array even when it has one element","Check for null handling: null is treated as missing and raises 'Field [...] is required' instead, so supply a real array","Verify the JSON body parses correctly (no nested quoting) before sending"],"exampleFix":"// before\n{ \"scope\": \"blocks\", \"ids\": \"20240101120000-abcdefg\" }\n// after\n{ \"scope\": \"blocks\", \"ids\": [\"20240101120000-abcdefg\"] }","handlingStrategy":"validation","validationCode":"function assertStringArray(v) { if (!Array.isArray(v) || !v.every(x => typeof x === 'string')) throw new TypeError('field must be a string array'); }","typeGuard":"const isStringArray = (v) => Array.isArray(v) && v.every((x) => typeof x === 'string');","tryCatchPattern":"try { await fetchPost('/api/block/checkBlockRef', payload); } catch (e) { if (/should be of type \\[Array\\]/.test(e?.message)) { /* fix payload shape */ } else { throw e; } }","preventionTips":["Always wrap block IDs in arrays, even for a single ID","Centralize checkBlockRef calls in one helper that validates payload shape","Type the payload with a TypeScript interface so ids/exactIDs/deletedIDs/paths are string[]"],"tags":["api","validation","json","type-mismatch"],"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"}