siyuan-note/siyuan · error

table cell rich text projection length changed

Error message

table cell rich text projection length changed

What it means

The recursive sync over a table cell's projected inline nodes walks both the expected projection and the actual cell children in lockstep. This error means one list ended before the other — the actual cell contains fewer or more inline nodes than the expected projection, so positions cannot be matched.

Solutions

  1. Re-parse/re-render the document to rebuild the projection from the cell's source
  2. Undo the recent edit to the table cell (Ctrl+Z) or restore from block history
  3. Update clients/plugins that mutate table cell AST directly to regenerate projections after edits
  4. Restore the document from sync snapshot if corruption persists

Example fix

// before: cell has an extra inline node vs projection
// after: regenerate expected projection from the current fragment
expected, sources := parse.ProjectTableCellRichWithSources(fragment)
if nil != cell.FirstChild { sync(expected.FirstChild, cell.FirstChild) }
Defensive patterns

Strategy: validation

Validate before calling

if expected.ChildCount() != cell.ChildCount() {
  expected, sources = parse.ProjectTableCellRichWithSources(fragment)
}

Prevention

When it happens

Trigger: An edit inside a projected table cell added or deleted inline nodes (e.g. new text spans, removed math element) so the child counts differ; programmatic tree mutation without regenerating the projection.

Common situations: Plugin DOM/tree manipulation of table cells; paste operations into projected cells via older clients; concurrent edits merged by sync that changed node counts.

Understand the failure class

Background: "This is a bug, please report it": internal invariant violations, unreachable panics, and SNH errors explained — this error's family across 47 libraries.

Related errors


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

Appendix: source

Thrown at kernel/treenode/table_cell_rich.go:179

					}
					switch origin.Type {
					case ast.NodeCodeBlockCode:
						origin.Tokens = []byte(html.UnescapeString(actual.TextMarkTextContent) + "\n")
					case ast.NodeMathBlockContent:
						origin.Tokens = []byte(html.UnescapeString(actual.TextMarkInlineMathContent))
					default:
						parent, previous, next, first, last := origin.Parent, origin.Previous, origin.Next, origin.FirstChild, origin.LastChild
						*origin = *parse.CloneTableCellInline(actual)
						origin.Parent, origin.Previous, origin.Next, origin.FirstChild, origin.LastChild = parent, previous, next, first, last
					}
					changed = true
				}
				if e := sync(want.FirstChild, actual.FirstChild); nil != e {
					return e
				}
			}
			if want != nil || actual != nil {
				return fmt.Errorf("table cell rich text projection length changed")
			}
			return nil
		}
		if nil != cell.FirstChild {
			if err = sync(expected.FirstChild, cell.FirstChild); nil != err {
				return ast.WalkStop
			}
		}
		if changed {
			var content string
			if content, err = av.RenderTableCellRich(fragment); nil != err {
				return ast.WalkStop
			}
			updates[cell] = content
		}
		return ast.WalkSkipChildren
	})
	if nil != err {

View on GitHub (pinned to 9f775e8a12)