{"record":{"id":"289580e315e1092e","repo":"siyuan-note/siyuan","slug":"block-is-not-a-list-item","errorCode":null,"errorMessage":"block is not a list item","messagePattern":"block is not a list item","errorType":"validation","errorClass":null,"httpStatus":200,"severity":"error","filePath":"kernel/api/block_op.go","lineNumber":56,"sourceCode":"\t\tutil.BindJsonArg(\"dataType\", &input.DataType, true, true),\n\t\tutil.BindJsonArg(\"lockType\", &input.LockType, false, false),\n\t) {\n\t\treturn\n\t}\n\tif util.InvalidIDPattern(input.ID, ret) {\n\t\treturn input, false\n\t}\n\treturn input, true\n}\n\nfunc buildUpdatedTaskListItemBlockDOM(id, marker string, luteEngine *lute.Lute) (data string, err error) {\n\tblock, err := model.GetBlock(id, nil)\n\tif err != nil {\n\t\treturn \"\", errors.New(\"get block failed: \" + err.Error())\n\t}\n\n\tif \"NodeListItem\" != block.Type {\n\t\treturn \"\", errors.New(\"block is not a list item\")\n\t}\n\n\ttree, err := filesys.LoadTree(block.Box, block.Path, luteEngine)\n\tif err != nil {\n\t\treturn \"\", errors.New(\"load tree failed: \" + err.Error())\n\t}\n\n\tli := treenode.GetNodeInTree(tree, id)\n\tif li == nil {\n\t\treturn \"\", errors.New(\"block not found\")\n\t}\n\n\tif 3 != li.ListData.Typ {\n\t\treturn \"\", errors.New(\"block is not a task list item\")\n\t}\n\n\tif 1 != len(marker) {\n\t\treturn \"\", errors.New(\"task list item marker length should be 1\")","sourceCodeStart":38,"sourceCodeEnd":74,"githubUrl":"https://github.com/siyuan-note/siyuan/blob/afa823b6b4e4f183511e0bc0a3be93caa94c7c97/kernel/api/block_op.go#L38-L74","documentation":"Thrown by buildUpdatedTaskListItemBlockDOM (kernel/api/block_op.go) when the block loaded from the index has a Type other than \"NodeListItem\". The task-marker update endpoint only operates on list items; passing any other block type (paragraph, heading, code block, blockquote, embed...) is rejected before the tree is even loaded.","triggerScenarios":"POST /api/block/updateTaskListItemMarker with the id of a paragraph, heading, or any non-list block; passing a container block id (list itself) instead of the individual list item id; frontend gutter/checkbox handler wired to the wrong block after a DOM-to-id mapping mistake.","commonSituations":"A plugin toggles a checkbox it located by walking the DOM and grabs the parent paragraph; the block was converted from a list item to another type after the id was captured; batch updates iterate over a selection that includes non-list blocks.","solutions":["Fetch the block first (/api/block/getBlockInfo) and check its type equals NodeListItem before calling","Target the specific list item block id, not its parent list or sibling content","Filter candidate ids client-side so only NodeListItem blocks are sent","If you need task semantics on another block type, convert it to a task list item in the editor first, then call"],"exampleFix":"// before\nfetchPost('/api/block/updateTaskListItemMarker', { id: paragraphId, marker: 'x' }); // \"block is not a list item\"\n\n// after\nconst info = await fetchPost('/api/block/getBlockInfo', { id });\nif (info.data.type === 'NodeListItem') {\n  fetchPost('/api/block/updateTaskListItemMarker', { id, marker: 'x' });\n}","handlingStrategy":"type-guard","validationCode":"const info = await fetchPost('/api/block/getBlockInfo', { id });\nif (info.data?.type !== 'NodeListItem') {\n  throw new Error(`block [${id}] is ${info.data?.type}, not a list item`);\n}\nawait fetchPost('/api/block/updateTaskListItemMarker', { id, marker });","typeGuard":"function isListItemBlock(b: { type: string } | null | undefined): b is { type: 'NodeListItem' } {\n  return b?.type === 'NodeListItem';\n}","tryCatchPattern":"if (e.message === 'block is not a list item') { /* re-select the target: use the list item's own id, not a parent/sibling */ }","preventionTips":["Map DOM elements to their own block id, never the enclosing block","Re-fetch block info when a user selection may have changed block types","Filter batch id lists by type before sending"],"tags":["block","task-list","validation","api","siyuan"],"backgroundTag":"wrong-block-type","analyzedSha":"afa823b6b4e4f183511e0bc0a3be93caa94c7c97","analyzedAt":"2026-08-18T17:04:10.865Z","schemaVersion":2},"datasetVersion":"2026-08-31T22:30:34.772Z"}