siyuan-note/siyuan · error · Error

Unsupported table cell rich text format

Error message

Unsupported table cell rich text format

What it means

A sentinel validation error from the table cell rich-text decoder: decodeTableCellRich only accepts kramdown-format cells whose embedded spec/format fields match what it supports (spec 1, format "kramdown"), and the base64url-decoded JSON payload named a different spec or format version. The input at fault is the encoded string passed in — e.g. a cell attribute written by a newer SiYuan version, hand-edited .sy content, or data produced by a plugin using another markup format. The preceding regex guard already rejects malformed base64; this error specifically means well-formed payload, unsupported schema.

Solutions

  1. Wrap decodeTableCellRich calls in try-catch and fall back to rendering the cell as plain kramdown text when the format is unrecognized
  2. Version-gate new formats by incrementing spec and keeping decoders for older specs so existing notebooks keep rendering
  3. Validate plugin/third-party writes that produce cell rich-text attributes against the documented spec 1 kramdown shape
  4. On upgrade paths, migrate old cell payloads explicitly rather than relying on the decoder to guess
Defensive patterns

Strategy: validation

When it happens

Trigger: Thrown at app/src/protyle/util/tableCellRichValue.ts:25 when the library encounters an invalid state.

Common situations: See trigger scenarios.


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

Appendix: source

Thrown at app/src/protyle/util/tableCellRichValue.ts:25

    content: string;
}

export const encodeTableCellRich = (content: string) => {
    const bytes = new TextEncoder().encode(JSON.stringify({spec: 1, format: "kramdown", content}));
    let binary = "";
    bytes.forEach(byte => binary += String.fromCharCode(byte));
    return btoa(binary).replace(/\+/g, "-").replace(/\//g, "_").replace(/=+$/, "");
};

export const decodeTableCellRich = (encoded: string): TableCellRich => {
    if (!/^[A-Za-z0-9_-]+$/.test(encoded)) {
        throw new Error("Invalid table cell rich text payload");
    }
    const bytes = Uint8Array.from(atob(encoded.replace(/-/g, "+").replace(/_/g, "/")), char => char.charCodeAt(0));
    const value = JSON.parse(new TextDecoder("utf-8", {fatal: true}).decode(bytes));
    if (!value || Object.keys(value).length !== 3 || value.spec !== 1 || value.format !== "kramdown" ||
        typeof value.content !== "string" || value.content.includes("\u0000")) {
        throw new Error("Unsupported table cell rich text format");
    }
    return value;
};

View on GitHub (pinned to 9f775e8a12)