siyuan-note/siyuan · error
Field [notebook] should be of type [String]
Error message
Field [notebook] should be of type [String]
What it means
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".
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")
Example fix
// before
{ "scope": "notebook", "notebook": 20240101120000, "ids": [] }
// after
{ "scope": "notebook", "notebook": "20240101120000-abcdefg", "ids": [] } Defensive patterns
Strategy: validation
Validate before calling
if (notebook !== null && notebook !== undefined && typeof notebook !== 'string') throw new TypeError('notebook must be a string'); Type guard
const isNotebookId = (v) => typeof v === 'string' && /^\d{14}-[0-9a-z]{7}$/.test(v); Try / catch
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); } } Prevention
- 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
When it happens
Trigger: POST /api/block/checkBlockRef with "notebook": 20240101 (numeric notebook ID), "notebook": {"id": "..."}, or "notebook": true.
Common situations: 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.
Understand the failure class
Background: Type mismatch errors: IllegalArgumentException, TypeError and type guards across 150 open-source libraries — this error's family across 150 libraries.
Related errors
- block [ ] type is locked: expected , got
- Field [level] should be of type [Number]
- Field [preview] should be of type [Boolean]
- Field [ ] should be of type [Array]
- Field [ ] should be of type [ ]
AI-assisted analysis of siyuan-note/siyuan@9f775e8a12 (2026-09-19).
Data as JSON: /api/errors/e52df745af3665cf.
Report an issue: GitHub.
Appendix: source
Thrown at kernel/apicontract/block_remaining.go:138
request.Paths, err = readArray("paths", true, true)
return
case "notebook":
// 附带块 ID 只参与租约准入,沿用仅收集字符串的规则。
var entries []json.RawMessage
if json.Unmarshal(fields["ids"], &entries) == nil {
for _, entry := range entries {
var id string
if !bytes.Equal(entry, []byte("null")) && json.Unmarshal(entry, &id) == nil {
request.IDs = append(request.IDs, id)
}
}
}
default:
return request, errors.New("invalid block ref check scope")
}
if raw := fields["notebook"]; len(raw) != 0 && !bytes.Equal(raw, []byte("null")) {
if json.Unmarshal(raw, &request.Notebook) != nil {
return request, errors.New("Field [notebook] should be of type [String]")
}
} else if request.Scope == "notebook" {
return request, errors.New("Field [notebook] is required")
}
if request.Scope == "notebook" {
request.Notebook = strings.TrimSpace(request.Notebook)
if request.Notebook == "" {
return request, errors.New("Field [notebook] must not be empty")
}
}
_ = json.Unmarshal(fields["id"], &request.ID)
return
}
func decodeHeadingLevel(reader io.Reader) (request HeadingLevelRequest, err error) {
fields, err := blockRequestFields(reader, "/api/block/getHeadingLevelTransaction")
if err != nil {
return request, errView on GitHub (pinned to 9f775e8a12)