hcengineering/platform · error

Token type `${node.type}` not supported by Markdown renderer

Error message

Token type `${node.type}` not supported by Markdown renderer

What it means

The Markdown serializer's render() method dispatches to a per-node-type renderer looked up in this.nodes. If a node's type has no registered renderer, the serializer cannot produce Markdown for it and throws this error instead of silently emitting wrong output.

Source

Thrown at foundations/core/packages/text-markdown/src/serializer.ts:557

  // :: (string, ?bool)
  // Add the given text to the document. When escape is not `false`,
  // it will be escaped.
  text (text: string, escape = false): void {
    const lines = text.split('\n')
    for (let i = 0; i < lines.length; i++) {
      const startOfLine = this.atBlank() || this.closed
      this.write('')
      this.out += escape ? this.esc(lines[i], startOfLine) : lines[i]
      if (i !== lines.length - 1) this.out += '\n'
    }
  }

  // :: (Node)
  // Render the given node as a block.
  render (node: MarkupNode, parent: MarkupNode, index: number): void {
    if (this.nodes[node.type] === undefined) {
      throw new Error('Token type `' + node.type + '` not supported by Markdown renderer')
    }
    this.nodes[node.type](this, node, parent, index)
  }

  // :: (Node)
  // Render the contents of `parent` as block nodes.
  renderContent (parent: MarkupNode): void {
    nodeContent(parent).forEach((node: MarkupNode, i: number) => {
      this.render(node, parent, i)
    })
  }

  reorderMixableMark (state: InlineState, mark: MarkupMark, i: number, len: number): void {
    for (let j = 0; j < state.active.length; j++) {
      const other = state.active[j]
      if (!this.marks[other.type].mixable || this.checkSwitchMarks(i, j, state, mark, other, len)) {
        break
      }

View on GitHub (pinned to 63e28dc964)

Solutions

  1. Remove or convert unsupported node types before rendering (e.g. map them to supported paragraphs/text)
  2. Register a renderer for the node type in the serializer's nodes table
  3. Check document contents with a filter step that drops or rewrites unknown node types

Example fix

// before
render(doc) // doc contains custom 'embed' node -> throws
// after
const filtered = doc.filter(n => supportedTypes.has(n.type))
render(filtered)
Defensive patterns

Strategy: validation

Validate before calling

const supported = new Set(['paragraph','heading','bulletList','orderedList','listItem','codeBlock','blockquote'])
if (!supported.has(node.type)) throw new Error(`node ${node.type} not renderable to markdown`)

Type guard

function isRenderable(node: { type: string }, supported: Set<string>): boolean {
  return supported.has(node.type)
}

Try / catch

try {
  serializer.render(node, parent, index)
} catch (e) {
  if (e.message.includes('not supported by Markdown renderer')) {
    return fallbackRender(node)
  }
  throw e
}

Prevention

When it happens

Trigger: Passing a document containing a node type the Markdown renderer does not support (e.g. a custom node, hard-break, or a node kind only valid in HTML/other renderers) to render(), called via renderContent, checkOpenMarks, or renderListItem.

Common situations: Custom node types added via plugins, documents round-tripped from other formats introducing unsupported nodes, or upgrading the document schema without updating renderer node registrations.

Related errors


AI-assisted analysis of hcengineering/platform@63e28dc964 (2026-08-29). Data as JSON: /api/errors/8f12b1d6ebbea8ce. Report an issue: GitHub.