siyuan-note/siyuan · error
createEmptyParagraph must be a boolean
Error message
createEmptyParagraph must be a boolean
What it means
UnmarshalJSON for the block delete/transaction options rejects a decoded payload whose createEmptyParagraph field is absent or not a boolean. The decoder runs with DisallowUnknownFields and then explicitly requires the pointer field to be non-nil, so a missing key or a non-boolean value (e.g. a string "true") fails. This enforces an explicit API contract for the transaction options shape.
Solutions
- Add createEmptyParagraph as a real JSON boolean (true or false) to the options object
- Remove any JSON null value for the field and replace it with an explicit boolean
- Check for typos or case mismatches in the key name (the decoder also rejects unknown fields)
- Update older client code or generated schemas that predate the mandatory field
Example fix
// before
{"actions":[{"action":"delete","srcIDs":["20240101120000-abc"],"createEmptyParagraph":"true"}]}
// after
{"actions":[{"action":"delete","srcIDs":["20240101120000-abc"],"createEmptyParagraph":true}]} Defensive patterns
Strategy: validation
Validate before calling
function isBool(v) { return typeof v === "boolean"; }
if (!payload.actions.every(a => a.createEmptyParagraph === undefined || isBool(a.createEmptyParagraph))) throw new Error("createEmptyParagraph must be boolean"); Type guard
function hasBooleanFlag(o) { return typeof o?.createEmptyParagraph === "boolean"; } Try / catch
try { await postTransaction(payload); } catch (e) { if (String(e).includes("createEmptyParagraph must be a boolean")) { payload.actions.forEach(a => { if (typeof a.createEmptyParagraph !== "boolean") a.createEmptyParagraph = false; }); await postTransaction(payload); } else throw e; } Prevention
- Always include createEmptyParagraph: true|false explicitly in delete actions
- Never send JSON null for boolean flags
- Keep client request types in sync with the kernel contract
- Lint payloads with a JSON schema that marks the field required and type boolean
When it happens
Trigger: Calling the block transaction API with a JSON payload that omits createEmptyParagraph, or sends it as a non-boolean (string, number, object, or JSON null). JSON null is notable: Go decodes null into a *bool as nil, so {"createEmptyParagraph": null} also triggers this error.
Common situations: Hand-written client payloads where the flag was considered optional; older clients built before the field became mandatory; templated request bodies where the key was accidentally dropped; sending quoted booleans ("true") from loosely typed languages.
Understand the failure class
Background: "Must be a positive integer", "Invalid value", "Unsupported": the invalid-argument-value error family, when a library rejects the value you pass — this error's family across 35 libraries.
Related errors
- Field [ ] has an invalid type
- Field [ ] must not be null
- builtin color must not be null
- builtin style must not be null
- Conf.Language(317)
AI-assisted analysis of siyuan-note/siyuan@9f775e8a12 (2026-09-19).
Data as JSON: /api/errors/8b0186fa01b0a639.
Report an issue: GitHub.
Appendix: source
Thrown at kernel/apicontract/block_transaction.go:56
func (d *BlockOperationData) UnmarshalJSON(data []byte) error {
data = bytes.TrimSpace(data)
*d = BlockOperationData{}
if bytes.Equal(data, []byte("null")) {
return nil
}
if len(data) > 0 && data[0] == '"' {
return json.Unmarshal(data, &d.text)
}
var options struct {
CreateEmptyParagraph *bool `json:"createEmptyParagraph"`
}
decoder := json.NewDecoder(bytes.NewReader(data))
decoder.DisallowUnknownFields()
if err := decoder.Decode(&options); err != nil {
return err
}
if options.CreateEmptyParagraph == nil {
return fmt.Errorf("createEmptyParagraph must be a boolean")
}
d.deleteOptions = &BlockDeleteData{CreateEmptyParagraph: *options.CreateEmptyParagraph}
return nil
}
// BlockOperationResult 保留块操作返回的文本、块 ID 数组和空值三种载荷。
type BlockOperationResult struct {
text *string
ids []string
}
func (r BlockOperationResult) MarshalJSON() ([]byte, error) {
if r.text != nil {
return json.Marshal(*r.text)
}
return json.Marshal(r.ids)
}
View on GitHub (pinned to 9f775e8a12)