{"record":{"id":"8b0186fa01b0a639","repo":"siyuan-note/siyuan","slug":"createemptyparagraph-must-be-a-boolean","errorCode":null,"errorMessage":"createEmptyParagraph must be a boolean","messagePattern":"createEmptyParagraph must be a boolean","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"kernel/apicontract/block_transaction.go","lineNumber":56,"sourceCode":"func (d *BlockOperationData) UnmarshalJSON(data []byte) error {\n\tdata = bytes.TrimSpace(data)\n\t*d = BlockOperationData{}\n\tif bytes.Equal(data, []byte(\"null\")) {\n\t\treturn nil\n\t}\n\tif len(data) > 0 && data[0] == '\"' {\n\t\treturn json.Unmarshal(data, &d.text)\n\t}\n\tvar options struct {\n\t\tCreateEmptyParagraph *bool `json:\"createEmptyParagraph\"`\n\t}\n\tdecoder := json.NewDecoder(bytes.NewReader(data))\n\tdecoder.DisallowUnknownFields()\n\tif err := decoder.Decode(&options); err != nil {\n\t\treturn err\n\t}\n\tif options.CreateEmptyParagraph == nil {\n\t\treturn fmt.Errorf(\"createEmptyParagraph must be a boolean\")\n\t}\n\td.deleteOptions = &BlockDeleteData{CreateEmptyParagraph: *options.CreateEmptyParagraph}\n\treturn nil\n}\n\n// BlockOperationResult 保留块操作返回的文本、块 ID 数组和空值三种载荷。\ntype BlockOperationResult struct {\n\ttext *string\n\tids  []string\n}\n\nfunc (r BlockOperationResult) MarshalJSON() ([]byte, error) {\n\tif r.text != nil {\n\t\treturn json.Marshal(*r.text)\n\t}\n\treturn json.Marshal(r.ids)\n}\n","sourceCodeStart":38,"sourceCodeEnd":74,"githubUrl":"https://github.com/siyuan-note/siyuan/blob/9f775e8a12daef8255556097396f9b2739078892/kernel/apicontract/block_transaction.go#L38-L74","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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"],"exampleFix":"// before\n{\"actions\":[{\"action\":\"delete\",\"srcIDs\":[\"20240101120000-abc\"],\"createEmptyParagraph\":\"true\"}]}\n// after\n{\"actions\":[{\"action\":\"delete\",\"srcIDs\":[\"20240101120000-abc\"],\"createEmptyParagraph\":true}]}","handlingStrategy":"validation","validationCode":"function isBool(v) { return typeof v === \"boolean\"; }\nif (!payload.actions.every(a => a.createEmptyParagraph === undefined || isBool(a.createEmptyParagraph))) throw new Error(\"createEmptyParagraph must be boolean\");","typeGuard":"function hasBooleanFlag(o) { return typeof o?.createEmptyParagraph === \"boolean\"; }","tryCatchPattern":"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; }","preventionTips":["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"],"tags":["json","validation","api-contract"],"backgroundTag":"invalid-argument-value","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"}