siyuan-note/siyuan · error
Field [notebook] is required
Error message
Field [notebook] is required
What it means
When /api/block/checkBlockRef is called with scope "notebook", the notebook field is mandatory. The kernel raises this error when notebook is absent, an empty string, or an explicit null while scope is "notebook". Scopes "blocks" and "documents" do not require notebook and never hit this branch.
Solutions
- Always include the notebook ID string when scope is "notebook"
- Guard the call site: only send scope "notebook" after a notebook has been selected
- Use scope "blocks" or "documents" instead if the operation is not notebook-wide
Example fix
// before
await fetchPost("/api/block/checkBlockRef", { scope: "notebook", ids });
// after
await fetchPost("/api/block/checkBlockRef", { scope: "notebook", notebook, ids }); Defensive patterns
Strategy: validation
Validate before calling
if (payload.scope === 'notebook' && !payload.notebook) throw new Error('notebook is required when scope is "notebook"'); Type guard
const notebookScopeReady = (p) => p.scope !== 'notebook' || (typeof p.notebook === 'string' && p.notebook.length > 0);
Try / catch
try { await fetchPost('/api/block/checkBlockRef', payload); } catch (e) { if (/Field \[notebook\] is required/.test(e?.message)) { /* prompt for notebook or switch scope */ } } Prevention
- Build payloads through a helper that enforces the scope/field pairing
- Disable notebook-scope actions in the UI until a notebook is selected
- Default to scope 'blocks' when no notebook context exists
When it happens
Trigger: POST /api/block/checkBlockRef with {"scope":"notebook"} and no notebook key; {"scope":"notebook","notebook":null}; {"scope":"notebook","notebook":""}.
Common situations: Refactoring code from scope "blocks" to "notebook" without adding the notebook parameter; a UI state where no notebook is selected yet the check still fires; null sent because an earlier layer conflated 'absent' with 'nullable'.
Understand the failure class
Background: "missing required argument" and "the following required arguments were not provided": what required-argument errors mean and how to fix them — this error's family across 20 libraries.
Related errors
- Field [conf] is required
- Field [id] should be of type [String]
- Field [ ] is required
- left document version is required
- [paths] is required
AI-assisted analysis of siyuan-note/siyuan@9f775e8a12 (2026-09-19).
Data as JSON: /api/errors/f2ebc999cf40c5e8.
Report an issue: GitHub.
Appendix: source
Thrown at kernel/apicontract/block_remaining.go:141
// 附带块 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, err
}
if len(fields["level"]) == 0 || bytes.Equal(fields["level"], []byte("null")) || json.Unmarshal(fields["level"], &request.Level) != nil {
return request, errors.New("Field [level] should be of type [Number]")View on GitHub (pinned to 9f775e8a12)