{"record":{"id":"9f639d20ebfe36e6","repo":"siyuan-note/siyuan","slug":"block-write-failed-empty-block-id","errorCode":null,"errorMessage":"block write failed: empty block ID","messagePattern":"block write failed: empty block ID","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"kernel/cli/cmd/block.go","lineNumber":321,"sourceCode":"\t\t\tParentID: parentID,\n\t\t}\n\t\tif err = model.PerformTxSync(&model.Transaction{DoOperations: []*model.Operation{operation}}); err != nil {\n\t\t\treturn err\n\t\t}\n\t\tif bt := treenode.GetBlockTree(parentID); bt != nil {\n\t\t\tmodel.AppendPushReloadProtyleEntry(bt.RootID)\n\t\t}\n\t\treturn printBlockWriteResult(operation.ID)\n\t},\n}\n\nfunc printBlockWriteResult(id string) error {\n\treturn writeBlockWriteResult(os.Stdout, id)\n}\n\nfunc writeBlockWriteResult(output io.Writer, id string) error {\n\tif id == \"\" {\n\t\treturn fmt.Errorf(\"block write failed: empty block ID\")\n\t}\n\tif outputFormat == \"json\" {\n\t\tdata, err := json.MarshalIndent(map[string]string{\"id\": id}, \"\", \"  \")\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t\t_, err = fmt.Fprintln(output, string(data))\n\t\treturn err\n\t}\n\t_, err := fmt.Fprintln(output, id)\n\treturn err\n}\n\nvar blockUpdateCmd = &cobra.Command{\n\tUse:   \"update --id <id> [--data <markdown> | --file <path>]\",\n\tShort: \"Update block\",\n\tRunE: func(cmd *cobra.Command, args []string) error {\n\t\tid, _ := cmd.Flags().GetString(\"id\")","sourceCodeStart":303,"sourceCodeEnd":339,"githubUrl":"https://github.com/siyuan-note/siyuan/blob/afa823b6b4e4f183511e0bc0a3be93caa94c7c97/kernel/cli/cmd/block.go#L303-L339","documentation":"Returned by writeBlockWriteResult (kernel/cli/cmd/block.go:321), the shared printer invoked by insert/append/prepend after a successful write. It asserts that the model-layer operation carried a non-empty block ID; an empty ID means the write path returned an operation without a usable identifier, so the command refuses to print a meaningless result. This is an internal contract violation between the CLI layer and model.InsertBlock/AppendBlock/PrependBlock, not a flag-usage mistake.","triggerScenarios":"A write that completes without producing a created block — e.g. empty/whitespace-only --data or --file content that yields no block to insert; an edge case in the model transaction returning a zero-valued operation; a version skew where the operation struct stopped populating ID as the CLI expects.","commonSituations":"Scripted writes where the data variable is empty but present (so earlier guards pass); feeding an empty file via --file; upgrading the kernel while an older CLI wrapper kept running.","solutions":["Check the payload first: ensure --data is non-empty (not just present) or the --file has content — an empty payload can complete the write while producing no block ID","Re-run with --dry-run and echo the exact payload to confirm what is being sent","Inspect the kernel log around the failed command for the underlying transaction result","If the payload is valid and the error persists, capture the exact command plus payload and report it — an empty operation.ID from the model layer indicates a defect worth filing"],"exampleFix":"# before: empty-but-present payload passes earlier guards\nsiyuan-kernel block append --parent 20260605100657-v080a4j --data \"$BODY\"\n# after: refuse empty input before writing\n[ -n \"$BODY\" ] || { echo 'empty body' >&2; exit 2; }\nsiyuan-kernel block append --parent 20260605100657-v080a4j --data \"$BODY\"","handlingStrategy":"try-catch","validationCode":"# bash: empty-but-present payloads are the main avoidable cause\n[ -n \"${DATA// /[ ]}\" ] || { echo 'refusing to write empty content' >&2; exit 2; }\n[ -z \"$FILE\" ] || [ -s \"$FILE\" ] || { echo \"file empty: $FILE\" >&2; exit 2; }\nsiyuan-kernel block append --parent \"$PARENT\" --data \"$DATA\"","typeGuard":null,"tryCatchPattern":"In shell: `if ! out=$(siyuan-kernel block append ... 2>&1); then case \"$out\" in *'empty block ID'*) echo 'write produced no block — check payload and kernel log' >&2; exit 3;; esac; fi` — treat it as a suspected defect: do not retry the same write (risk of duplication on partial success), preserve the command and payload for a bug report.","preventionTips":["Never call a write subcommand with empty/whitespace-only --data or an empty --file — earlier flag guards will not catch it","Verify the document state after any write that errors ambiguously (block children) before retrying","Keep kernel and CLI versions in lockstep — this error signals an internal contract between them","Capture kernel logs alongside the command output so empty-ID cases can be diagnosed offline"],"tags":["cli","blocks","write","internal-error","invariant","siyuan"],"backgroundTag":"empty-operation-result","analyzedSha":"afa823b6b4e4f183511e0bc0a3be93caa94c7c97","analyzedAt":"2026-08-18T17:04:10.865Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}