{"record":{"id":"1879b7ba134c063c","repo":"siyuan-note/siyuan","slug":"field-s-should-be-of-type-s-inline-style-input","errorCode":null,"errorMessage":"Field [%s] should be of type [%s]","messagePattern":"Field \\[(.+?)\\] should be of type \\[(.+?)\\]","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"kernel/apicontract/inline_style_input.go","lineNumber":49,"sourceCode":"\t\treturn\n\t}\n\tdata, err := json.Marshal(normalized)\n\tif err == nil {\n\t\terr = json.Unmarshal(data, &value)\n\t}\n\treturn\n}\n\nfunc legacyField[T any](fields map[string]json.RawMessage, key, kind string, required bool) (value T, err error) {\n\traw := fields[key]\n\tif len(raw) == 0 || bytes.Equal(raw, []byte(\"null\")) {\n\t\tif required {\n\t\t\terr = fmt.Errorf(\"Field [%s] is required\", key)\n\t\t}\n\t\treturn\n\t}\n\tif json.Unmarshal(raw, &value) != nil {\n\t\terr = fmt.Errorf(\"Field [%s] should be of type [%s]\", key, kind)\n\t}\n\treturn\n}\n\nfunc init() {\n\tSetInlineStyles.decodeRequest = func(reader io.Reader) (request SetInlineStylesRequest, err error) {\n\t\tfields, err := blockRequestFields(reader, \"/api/storage/setInlineStyles\")\n\t\tif err != nil {\n\t\t\treturn request, err\n\t\t}\n\t\tversion, err := legacyField[float64](fields, \"version\", \"Number\", true)\n\t\tif err != nil {\n\t\t\treturn request, err\n\t\t}\n\t\tif _, err = legacyField[[]json.RawMessage](fields, \"styles\", \"Array\", true); err != nil {\n\t\t\treturn request, err\n\t\t}\n\t\tapp, err := legacyField[string](fields, \"app\", \"String\", false)","sourceCodeStart":31,"sourceCodeEnd":67,"githubUrl":"https://github.com/siyuan-note/siyuan/blob/9f775e8a12daef8255556097396f9b2739078892/kernel/apicontract/inline_style_input.go#L31-L67","documentation":"legacyField decodes a field into a typed value; when json.Unmarshal into the target type fails it reports 'Field [<key>] should be of type [<kind>]'. This is the generic wrong-type error for legacy-decoded requests, telling the caller which field was sent with an incompatible JSON type.","triggerScenarios":"Sending a required field with the wrong JSON type, e.g. \"id\": 123 instead of a string, \"type\": true, or an array where a string is expected — for any endpoint decoded via legacyField (inline styles, AI params, AV requests, bazaar, copyFiles, DocVersionRef, graph).","commonSituations":"Dynamic languages coercing numbers/booleans into the payload; clients sending numeric IDs; copy-pasted payloads mixing types between endpoints.","solutions":["Send the field as the JSON type named in the message (e.g. wrap numbers in quotes for String fields)","Fix client serialization so the variable's type matches the contract","Check for double-encoded values (a JSON string containing JSON) which fail decoding into non-string targets","Consult the API contract in kernel/apicontract/ for each field's expected kind"],"exampleFix":"// before\n{\"id\": 12345, \"type\": \"id\"}\n// after\n{\"id\": \"12345\", \"type\": \"id\"}","handlingStrategy":"type-guard","validationCode":"const isStr = (v) => typeof v === \"string\";\nif (!isStr(body.id)) body.id = String(body.id); // coerce numeric ids before sending","typeGuard":"const isString = (v) => typeof v === \"string\";\nconst assertString = (o, k) => { if (!isString(o[k])) throw new TypeError(`${k} must be a string`); };","tryCatchPattern":"try {\n  const resp = await fetch(url, {method: \"POST\", body: JSON.stringify(body)});\n  const out = await resp.json();\n} catch (e) {\n  if (String(e).includes(\"should be of type\")) {\n    console.error(\"Wrong field type:\", e.message); // fix the field's JSON type and retry once\n  } else {\n    throw e;\n  }\n}","preventionTips":["Coerce numbers to strings for String-typed fields before serialization","Enable strict typing in the client (TypeScript interfaces for each request body)","Avoid booleans/numbers for fields documented as String"],"tags":["api","validation","type-mismatch","json"],"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"}