{"record":{"id":"201a426bd01a342d","repo":"siyuan-note/siyuan","slug":"field-scope-should-be-of-type-string","errorCode":null,"errorMessage":"Field [scope] should be of type [String]","messagePattern":"Field \\[scope\\] should be of type \\[String\\]","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"kernel/apicontract/block_remaining.go","lineNumber":73,"sourceCode":"func blockRequestFields(reader io.Reader, path string) (fields map[string]json.RawMessage, err error) {\n\terr = json.NewDecoder(reader).Decode(&fields)\n\tif err != nil {\n\t\tif errors.Is(err, io.EOF) {\n\t\t\terr = errors.New(\"the request body is empty or truncated (EOF)\")\n\t\t}\n\t\terr = fmt.Errorf(\"Parses request [%s] failed: %s\", path, err)\n\t}\n\treturn\n}\n\nfunc decodeCheckBlockRef(reader io.Reader) (request CheckBlockRefRequest, err error) {\n\tfields, err := blockRequestFields(reader, \"/api/block/checkBlockRef\")\n\tif err != nil {\n\t\treturn request, err\n\t}\n\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 {","sourceCodeStart":55,"sourceCodeEnd":91,"githubUrl":"https://github.com/siyuan-note/siyuan/blob/9f775e8a12daef8255556097396f9b2739078892/kernel/apicontract/block_remaining.go#L55-L91","documentation":"The checkBlockRef endpoint's scope field, when present, must be a JSON string (or absent, in which case it defaults to \"blocks\"). Explicit JSON null also counts as a type error. This guards the scope selector that steers which reference kinds are checked.","triggerScenarios":"POSTing to /api/block/checkBlockRef with {\"scope\":123}, {\"scope\":null}, {\"scope\":[\"blocks\"]}, or any non-string value for scope.","commonSituations":"Clients sending null to mean 'unset' (omit the key instead), arrays built from multi-select UIs, or numeric enum constants from another API mapped onto scope.","solutions":["Send scope as a quoted string, e.g. {\"scope\":\"blocks\"} or the supported child-document scope value.","Omit the scope key entirely to get the \"blocks\" default.","Replace null with key omission on the client before serializing.","If the value comes from a select input, ensure it yields a single string, not an array or number."],"exampleFix":"// before\n{\"ids\": [\"20240101120000-abcdefg\"], \"scope\": null}\n// after\n{\"ids\": [\"20240101120000-abcdefg\"]} // scope omitted, defaults to \"blocks\"","handlingStrategy":"type-guard","validationCode":"if (\"scope\" in payload && (payload.scope === null || typeof payload.scope !== \"string\")) { delete payload.scope; }","typeGuard":"const isScope = (v) => typeof v === \"string\" && v.length > 0;","tryCatchPattern":"try {\n  await post(\"/api/block/checkBlockRef\", payload);\n} catch (e) {\n  if (String(e.message).includes(\"Field [scope] should be of type [String]\")) {\n    delete payload.scope; // fall back to the \"blocks\" default\n    await post(\"/api/block/checkBlockRef\", payload);\n  } else { throw e; }\n}","preventionTips":["Omit scope instead of sending null to mean 'unset'","Constrain UI selects for scope to string values only","Reject non-string scope values at the client boundary","Document the default (\"blocks\") so callers know omission is safe"],"tags":["json","type-mismatch","validation","api"],"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"}