{"record":{"id":"91fe9f9e6fba23f2","repo":"siyuan-note/siyuan","slug":"rich-text-source-belongs-to-a-table-cell","errorCode":null,"errorMessage":"rich text source belongs to a table cell","messagePattern":"rich text source belongs to a table cell","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"kernel/treenode/table_cell_rich.go","lineNumber":99,"sourceCode":"\tast.Walk(root, func(n *ast.Node, entering bool) ast.WalkStatus {\n\t\tif entering && nil != n.TableCellRich {\n\t\t\tret = true\n\t\t\treturn ast.WalkStop\n\t\t}\n\t\treturn ast.WalkContinue\n\t})\n\treturn\n}\n\n// ValidateTableCellRich 检查富文本源，未知格式和损坏数据不降级为行内内容。\nfunc ValidateTableCellRich(root *ast.Node) (err error) {\n\tast.Walk(root, func(n *ast.Node, entering bool) ast.WalkStatus {\n\t\tif !entering || nil == n.TableCellRich {\n\t\t\treturn ast.WalkContinue\n\t\t}\n\t\tif ast.NodeTableCell != n.Type || !n.ParentIs(ast.NodeTableRow) ||\n\t\t\t!(n.Parent.ParentIs(ast.NodeTable) || n.Parent.ParentIs(ast.NodeTableHead) && n.Parent.Parent.ParentIs(ast.NodeTable)) {\n\t\t\terr = fmt.Errorf(\"rich text source belongs to a table cell\")\n\t\t\treturn ast.WalkStop\n\t\t}\n\t\tif _, err = av.ParseTableCellRich(n.TableCellRich); nil != err {\n\t\t\treturn ast.WalkStop\n\t\t}\n\t\treturn ast.WalkSkipChildren\n\t})\n\treturn\n}\n\n// RefreshTableCellRichProjection 在源验证成功后重建行内投影，不修改源数据。\nfunc RefreshTableCellRichProjection(root *ast.Node) (err error) {\n\tast.Walk(root, func(n *ast.Node, entering bool) ast.WalkStatus {\n\t\tif !entering || nil == n.TableCellRich {\n\t\t\treturn ast.WalkContinue\n\t\t}\n\t\tvar fragment *parse.Tree\n\t\tif fragment, err = av.ParseTableCellRich(n.TableCellRich); nil != err {","sourceCodeStart":81,"sourceCodeEnd":117,"githubUrl":"https://github.com/siyuan-note/siyuan/blob/9f775e8a12daef8255556097396f9b2739078892/kernel/treenode/table_cell_rich.go#L81-L117","documentation":"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.","triggerScenarios":"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.","commonSituations":"Importing documents from converters that build table fragments incorrectly; hand-edited .sy files; plugin code that clones cell nodes out of their table context.","solutions":["Fix the source document so TableCellRich appears only on NodeTableCell nodes inside TableRow within a Table/TableHead.","Remove the stray TableCellRich attribute from nodes outside a table.","Re-import with a converter that emits complete Table > TableRow > TableCell structure, or restore from backup."],"exampleFix":null,"handlingStrategy":"validation","validationCode":"// before persisting, confirm structure: cell.type === 'NodeTableCell' && cell.parent.type === 'NodeTableRow' && row is inside a table","typeGuard":null,"tryCatchPattern":"if err := treenode.ValidateTableCellRich(root); err != nil {\n    // refuse to save/import; surface the invalid structure to the user\n    return err\n}","preventionTips":["Build table structures with the AST API instead of manual node assembly.","Never clone cell nodes out of their row/table context.","Test importers against tables containing rich-text cells."],"tags":["tables","rich-text","ast-structure","validation"],"backgroundTag":"incompatible-source-type","analyzedSha":"9f775e8a12daef8255556097396f9b2739078892","analyzedAt":"2026-09-19T03:17:15.984Z","contentChangedAt":"2026-09-19T03:17:15.984Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}