{"record":{"id":"e52df745af3665cf","repo":"siyuan-note/siyuan","slug":"field-notebook-should-be-of-type-string","errorCode":null,"errorMessage":"Field [notebook] should be of type [String]","messagePattern":"Field \\[notebook\\] should be of type \\[String\\]","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"kernel/apicontract/block_remaining.go","lineNumber":138,"sourceCode":"\t\trequest.Paths, err = readArray(\"paths\", true, true)\n\t\treturn\n\tcase \"notebook\":\n\t\t// 附带块 ID 只参与租约准入，沿用仅收集字符串的规则。\n\t\tvar entries []json.RawMessage\n\t\tif json.Unmarshal(fields[\"ids\"], &entries) == nil {\n\t\t\tfor _, entry := range entries {\n\t\t\t\tvar id string\n\t\t\t\tif !bytes.Equal(entry, []byte(\"null\")) && json.Unmarshal(entry, &id) == nil {\n\t\t\t\t\trequest.IDs = append(request.IDs, id)\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\tdefault:\n\t\treturn request, errors.New(\"invalid block ref check scope\")\n\t}\n\tif raw := fields[\"notebook\"]; len(raw) != 0 && !bytes.Equal(raw, []byte(\"null\")) {\n\t\tif json.Unmarshal(raw, &request.Notebook) != nil {\n\t\t\treturn request, errors.New(\"Field [notebook] should be of type [String]\")\n\t\t}\n\t} else if request.Scope == \"notebook\" {\n\t\treturn request, errors.New(\"Field [notebook] is required\")\n\t}\n\tif request.Scope == \"notebook\" {\n\t\trequest.Notebook = strings.TrimSpace(request.Notebook)\n\t\tif request.Notebook == \"\" {\n\t\t\treturn request, errors.New(\"Field [notebook] must not be empty\")\n\t\t}\n\t}\n\t_ = json.Unmarshal(fields[\"id\"], &request.ID)\n\treturn\n}\n\nfunc decodeHeadingLevel(reader io.Reader) (request HeadingLevelRequest, err error) {\n\tfields, err := blockRequestFields(reader, \"/api/block/getHeadingLevelTransaction\")\n\tif err != nil {\n\t\treturn request, err","sourceCodeStart":120,"sourceCodeEnd":156,"githubUrl":"https://github.com/siyuan-note/siyuan/blob/9f775e8a12daef8255556097396f9b2739078892/kernel/apicontract/block_remaining.go#L120-L156","documentation":"In /api/block/checkBlockRef, the optional notebook field must be a JSON string when present and non-null. The kernel returns this error when the value fails to unmarshal into a string (e.g. a number, boolean, or object). This check runs for all scopes, not just \"notebook\".","triggerScenarios":"POST /api/block/checkBlockRef with \"notebook\": 20240101 (numeric notebook ID), \"notebook\": {\"id\": \"...\"}, or \"notebook\": true.","commonSituations":"Storing notebook IDs as numbers in external scripts; passing a notebook config object instead of its ID string; template interpolation producing a non-string type.","solutions":["Send the notebook ID as a JSON string: \"notebook\": \"20240101120000-xyz\"","If the ID came from a numeric source, convert with String(notebookId) before building the payload","Pass null or omit the field entirely when the notebook is unknown (required only when scope is \"notebook\")"],"exampleFix":"// before\n{ \"scope\": \"notebook\", \"notebook\": 20240101120000, \"ids\": [] }\n// after\n{ \"scope\": \"notebook\", \"notebook\": \"20240101120000-abcdefg\", \"ids\": [] }","handlingStrategy":"validation","validationCode":"if (notebook !== null && notebook !== undefined && typeof notebook !== 'string') throw new TypeError('notebook must be a string');","typeGuard":"const isNotebookId = (v) => typeof v === 'string' && /^\\d{14}-[0-9a-z]{7}$/.test(v);","tryCatchPattern":"try { await fetchPost('/api/block/checkBlockRef', payload); } catch (e) { if (/Field \\[notebook\\] should be of type \\[String\\]/.test(e?.message)) { payload.notebook = String(payload.notebook); } }","preventionTips":["Treat notebook IDs as strings everywhere in client code","Type notebook as string | null in the request interface","Never pass notebook config objects where an ID string is expected"],"tags":["api","validation","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"}