siyuan-note/siyuan · error

task list item marker can not be [ or ]

Error message

task list item marker can not be [ or ]

What it means

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.

Source

Thrown at kernel/api/block_op.go:79

		return "", errors.New("load tree failed: " + err.Error())
	}

	li := treenode.GetNodeInTree(tree, id)
	if li == nil {
		return "", errors.New("block not found")
	}

	if 3 != li.ListData.Typ {
		return "", errors.New("block is not a task list item")
	}

	if 1 != len(marker) {
		return "", errors.New("task list item marker length should be 1")
	}

	liMarker := marker[0]
	if '[' == liMarker || ']' == liMarker {
		return "", errors.New("task list item marker can not be [ or ]")
	}

	markerNode := li.ChildByType(ast.NodeTaskListItemMarker)
	if nil == markerNode {
		return "", errors.New("task list item marker not found")
	}

	markerNode.TaskListItemMarker = liMarker
	markerNode.TaskListItemChecked = ' ' != markerNode.TaskListItemMarker

	treenode.RefreshUpdated(li)

	return luteEngine.RenderNodeBlockDOM(li), nil
}

func updateTaskListItemMarker(c *gin.Context) {
	ret := gulu.Ret.NewResult()
	defer c.JSON(http.StatusOK, ret)

View on GitHub (pinned to 251596fc0d)

Solutions

  1. Forward the inner status character of the GFM token: marker = gfmToken[1] (the middle char of '[x]').
  2. Whitelist allowed glyphs before the call: [' ', 'x', 'X'] or your custom set, excluding '[' and ']'.
  3. If building a UI toggle, send 'x' for on and ' ' (space) for off.

Example fix

// before
const marker = gfmToken[0] // yields '['
// after
const marker = gfmToken[1] // yields 'x' or ' '
Defensive patterns

Strategy: validation

Validate before calling

function nonBracketMarker(m) {
  return m.length === 1 && m !== '[' && m !== ']';
}

Type guard

function isSafeMarkerChar(c: unknown): c is string {
  return typeof c === 'string' && c.length === 1 && c !== '[' && c !== ']';
}

Try / catch

try { await updateTaskMarker(id, marker); }
catch (e) { if (/can not be \[ or \]/.test(e.msg)) { marker = marker === '[' || marker === ']' ? ' ' : marker; await updateTaskMarker(id, marker); } else throw e; }

Prevention

When it happens

Trigger: 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.

Common situations: 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.

Related errors


AI-assisted analysis of siyuan-note/siyuan@251596fc0d (2026-08-12). Data as JSON: /api/errors/859d2e71d3ee0a67. Report an issue: GitHub.