{"record":{"id":"859d2e71d3ee0a67","repo":"siyuan-note/siyuan","slug":"task-list-item-marker-can-not-be-or","errorCode":null,"errorMessage":"task list item marker can not be [ or ]","messagePattern":"task list item marker can not be \\[ or \\]","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"kernel/api/block_op.go","lineNumber":79,"sourceCode":"\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\")\n\t}\n\n\tliMarker := marker[0]\n\tif '[' == liMarker || ']' == liMarker {\n\t\treturn \"\", errors.New(\"task list item marker can not be [ or ]\")\n\t}\n\n\tmarkerNode := li.ChildByType(ast.NodeTaskListItemMarker)\n\tif nil == markerNode {\n\t\treturn \"\", errors.New(\"task list item marker not found\")\n\t}\n\n\tmarkerNode.TaskListItemMarker = liMarker\n\tmarkerNode.TaskListItemChecked = ' ' != markerNode.TaskListItemMarker\n\n\ttreenode.RefreshUpdated(li)\n\n\treturn luteEngine.RenderNodeBlockDOM(li), nil\n}\n\nfunc updateTaskListItemMarker(c *gin.Context) {\n\tret := gulu.Ret.NewResult()\n\tdefer c.JSON(http.StatusOK, ret)","sourceCodeStart":61,"sourceCodeEnd":97,"githubUrl":"https://github.com/siyuan-note/siyuan/blob/251596fc0de2f9528c00c224252fd073a99973f4/kernel/api/block_op.go#L61-L97","documentation":"Returned when the single-character `marker` passed to updateTaskListItemMarker is the literal '[' or ']' character. These brackets are the structural delimiters of a GFM task list marker (`[x]`) and are never valid as the status glyph itself, so the kernel rejects them at block_op.go:78 to prevent malformed checkbox rendering.","triggerScenarios":"POST /api/block/updateTaskListItemMarker with {\"marker\":\"[\"} or {\"marker\":\"]\"}. The check at block_op.go:78 fires after the length check passes (so len==1) but before the marker node is written.","commonSituations":"A caller that extracts the wrong index from a `[x]`/`[ ]` token (e.g. taking index 0 or 2 instead of index 1). Code that iterates characters of the GFM marker and forwards each one. Misreading the API as accepting the bracket pair.","solutions":["Forward the inner status character of the GFM token: marker = gfmToken[1] (the middle char of '[x]').","Whitelist allowed glyphs before the call: [' ', 'x', 'X'] or your custom set, excluding '[' and ']'.","If building a UI toggle, send 'x' for on and ' ' (space) for off."],"exampleFix":"// before\nconst marker = gfmToken[0] // yields '['\n// after\nconst marker = gfmToken[1] // yields 'x' or ' '","handlingStrategy":"validation","validationCode":"function nonBracketMarker(m) {\n  return m.length === 1 && m !== '[' && m !== ']';\n}","typeGuard":"function isSafeMarkerChar(c: unknown): c is string {\n  return typeof c === 'string' && c.length === 1 && c !== '[' && c !== ']';\n}","tryCatchPattern":"try { await updateTaskMarker(id, marker); }\ncatch (e) { if (/can not be \\[ or \\]/.test(e.msg)) { marker = marker === '[' || marker === ']' ? ' ' : marker; await updateTaskMarker(id, marker); } else throw e; }","preventionTips":["Never derive the marker from index 0 or 2 of a '[x]' token.","Use a fixed mapping: checked='x', unchecked=' '.","Unit-test the marker derivation against '[x]', '[ ]', '[X]'."],"tags":["api","task-list","validation","kernel"],"backgroundTag":null,"analyzedSha":"251596fc0de2f9528c00c224252fd073a99973f4","analyzedAt":"2026-08-12T21:18:37.123Z","schemaVersion":2},"datasetVersion":"2026-08-13T04:17:16.726Z"}