siyuan-note/siyuan · error

rich text source belongs to a table cell

Error message

rich text source belongs to a table cell

What it means

ValidateTableCellRich walks a parsed tree and enforces that any node carrying TableCellRich is genuinely a table cell: type NodeTableCell, direct child of a NodeTableRow, with the row inside a NodeTable (directly or via NodeTableHead). A cell-like node found outside this legal table structure fails with this error, and corrupted rich text is not silently downgraded to inline content.

Solutions

  1. Fix the source document so TableCellRich appears only on NodeTableCell nodes inside TableRow within a Table/TableHead.
  2. Remove the stray TableCellRich attribute from nodes outside a table.
  3. Re-import with a converter that emits complete Table > TableRow > TableCell structure, or restore from backup.
Defensive patterns

Strategy: validation

Validate before calling

// before persisting, confirm structure: cell.type === 'NodeTableCell' && cell.parent.type === 'NodeTableRow' && row is inside a table

Try / catch

if err := treenode.ValidateTableCellRich(root); err != nil {
    // refuse to save/import; surface the invalid structure to the user
    return err
}

Prevention

When it happens

Trigger: A tree where TableCellRich is attached to a non-cell node, a cell not parented by a row, or a row not nested in a table/table-head — e.g. pasted HTML producing malformed tables, or a generator emitting standalone cells.

Common situations: Importing documents from converters that build table fragments incorrectly; hand-edited .sy files; plugin code that clones cell nodes out of their table context.

Understand the failure class

Background: "is not a compatible type" / "cannot merge" errors: when a value's type doesn't match what the library requires — this error's family across 65 libraries.

Related errors


AI-assisted analysis of siyuan-note/siyuan@9f775e8a12 (2026-09-19). Data as JSON: /api/errors/91fe9f9e6fba23f2. Report an issue: GitHub.

Appendix: source

Thrown at kernel/treenode/table_cell_rich.go:99

	ast.Walk(root, func(n *ast.Node, entering bool) ast.WalkStatus {
		if entering && nil != n.TableCellRich {
			ret = true
			return ast.WalkStop
		}
		return ast.WalkContinue
	})
	return
}

// ValidateTableCellRich 检查富文本源,未知格式和损坏数据不降级为行内内容。
func ValidateTableCellRich(root *ast.Node) (err error) {
	ast.Walk(root, func(n *ast.Node, entering bool) ast.WalkStatus {
		if !entering || nil == n.TableCellRich {
			return ast.WalkContinue
		}
		if ast.NodeTableCell != n.Type || !n.ParentIs(ast.NodeTableRow) ||
			!(n.Parent.ParentIs(ast.NodeTable) || n.Parent.ParentIs(ast.NodeTableHead) && n.Parent.Parent.ParentIs(ast.NodeTable)) {
			err = fmt.Errorf("rich text source belongs to a table cell")
			return ast.WalkStop
		}
		if _, err = av.ParseTableCellRich(n.TableCellRich); nil != err {
			return ast.WalkStop
		}
		return ast.WalkSkipChildren
	})
	return
}

// RefreshTableCellRichProjection 在源验证成功后重建行内投影,不修改源数据。
func RefreshTableCellRichProjection(root *ast.Node) (err error) {
	ast.Walk(root, func(n *ast.Node, entering bool) ast.WalkStatus {
		if !entering || nil == n.TableCellRich {
			return ast.WalkContinue
		}
		var fragment *parse.Tree
		if fragment, err = av.ParseTableCellRich(n.TableCellRich); nil != err {

View on GitHub (pinned to 9f775e8a12)