siyuan-note/siyuan · error

invalid table cell rich text payload

Error message

invalid table cell rich text payload

What it means

A valid TableCellRich payload must be a JSON object with exactly three fields: spec, format, and content. If the payload fails to unmarshal as an object or has a field count other than 3, this error is thrown.

Solutions

  1. Regenerate the payload with exactly the three required keys: spec, format, content.
  2. Remove extra keys or add the missing ones so len(fields) == 3.
  3. Restore the document from history/backup if the payload was corrupted by an unknown tool.

Example fix

// before
{"content": "text"}
// after
{"spec": "4", "format": "markdown", "content": "text"}
Defensive patterns

Strategy: validation

Validate before calling

const keys = Object.keys(payload);
if (keys.length !== 3 || !['spec','format','content'].every(k => k in payload)) { /* reject payload before writing */ }

Type guard

function isTableCellRichPayload(v) {
  return v !== null && typeof v === 'object' && !Array.isArray(v) &&
    Object.keys(v).length === 3 && 'spec' in v && 'format' in v && 'content' in v;
}

Prevention

When it happens

Trigger: checkTableCellRichJSON parses a TableCellRich value that is not a JSON object (array/string/number) or an object with fewer/more than 3 keys — e.g. a hand-written payload with only {content} or extra metadata keys.

Common situations: Third-party generators producing an outdated or partial rich-text payload shape; manual edits to .sy JSON; mixing payload formats between kernel versions.

Understand the failure class

Background: Schema validation failed / invalid input schema: payload rejected because its shape doesn't match the expected schema — this error's family across 28 libraries.

Related errors


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

Appendix: source

Thrown at kernel/treenode/table_cell_rich.go:41

		Children      []json.RawMessage
	}
	var check func(json.RawMessage, string) error
	check = func(raw json.RawMessage, context string) error {
		var node rawNode
		if err := json.Unmarshal(raw, &node); nil != err {
			return err
		}
		if len(node.TableCellRich) > 0 {
			if !utf8.Valid(node.TableCellRich) {
				return fmt.Errorf("table cell rich text payload is not UTF-8")
			}
			version, _ := strconv.Atoi(spec)
			if version < 4 || node.Type != "NodeTableCell" || context != "row" {
				return fmt.Errorf("invalid table cell rich text document spec [%s]", spec)
			}
			var fields map[string]json.RawMessage
			if err := json.Unmarshal(node.TableCellRich, &fields); nil != err || len(fields) != 3 {
				return fmt.Errorf("invalid table cell rich text payload")
			}
			for _, name := range []string{"spec", "format", "content"} {
				if len(fields[name]) == 0 || bytes.Equal(bytes.TrimSpace(fields[name]), []byte("null")) {
					return fmt.Errorf("missing table cell rich text field [%s]", name)
				}
			}
			var rich ast.TableCellRich
			if err := json.Unmarshal(node.TableCellRich, &rich); nil != err {
				return err
			}
			if _, err := av.ParseTableCellRich(&rich); nil != err {
				return err
			}
		}
		childContext := ""
		switch node.Type {
		case "NodeTable":
			childContext = "table"

View on GitHub (pinned to 9f775e8a12)