siyuan-note/siyuan · error
Field [id] should be of type [String]
Error message
Field [id] should be of type [String]
What it means
When /api/block/getHeadingLevelTransaction is called without a valid ids array, the kernel falls back to the singular id field, which must be a non-null JSON string. This error fires when id is missing, null, or not a string, i.e. neither a valid ids array nor a valid id string was supplied.
Solutions
- Provide either a valid ids array or a single id string block ID with every call
- If sending ids, make sure it is a real JSON array (not a comma-joined string) so the correct branch is taken
- Guard the call site so it only fires when a target block selection exists
Example fix
// before
await fetchPost("/api/block/getHeadingLevelTransaction", { level: 2 });
// after
await fetchPost("/api/block/getHeadingLevelTransaction", { level: 2, id: "20240101120000-abcdefg" }); Defensive patterns
Strategy: validation
Validate before calling
if (!Array.isArray(payload.ids) && typeof payload.id !== 'string') throw new TypeError('provide either ids array or id string'); Type guard
const hasTarget = (p) => (Array.isArray(p.ids) && p.ids.length > 0) || typeof p.id === 'string';
Try / catch
try { await fetchPost('/api/block/getHeadingLevelTransaction', payload); } catch (e) { if (/Field \[id\] should be of type \[String\]/.test(e?.message)) { /* read block ID from the active editor before retrying */ } } Prevention
- Always attach a target (ids array or id string) to heading-level requests
- When batching, send ids as a JSON array; do not join IDs with commas into a string
- Gate the call on the editor having an active block selection
When it happens
Trigger: POST /api/block/getHeadingLevelTransaction with {"level":2} and neither ids nor id; {"level":2,"id":null}; "id" given as a number; ids present but not a JSON array (e.g. a string), which skips the array branch and then fails the id fallback.
Common situations: Omitting both target fields after refactoring a single-block call to batch form (or vice versa); ids mistakenly sent as a comma-joined string so the array branch fails silently; a null id passed through from an unselected editor state.
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 [notebook] is required
- 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/b4db87d5ed9916f9.
Report an issue: GitHub.
Appendix: source
Thrown at kernel/apicontract/block_remaining.go:176
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]")
}
var entries []json.RawMessage
if raw := fields["ids"]; len(raw) > 0 && !bytes.Equal(raw, []byte("null")) && json.Unmarshal(raw, &entries) == nil {
request.IDs = []string{}
seen := map[string]bool{}
for _, entry := range entries {
var id string
if bytes.Equal(entry, []byte("null")) || json.Unmarshal(entry, &id) != nil {
return request, errors.New("Field [ids] should contain strings")
}
if !seen[id] {
request.IDs = append(request.IDs, id)
seen[id] = true
}
}
} else if len(fields["id"]) == 0 || bytes.Equal(fields["id"], []byte("null")) || json.Unmarshal(fields["id"], &request.ID) != nil {
return request, errors.New("Field [id] should be of type [String]")
}
return
}
View on GitHub (pinned to 9f775e8a12)