mermaid-js/mermaid · error · MermaidParseError

Parsing failed: ${lexerErrors} ${parserErrors}

Error message

Parsing failed: ${lexerErrors} ${parserErrors}

What it means

Thrown by parse() in packages/parser/src/parse.ts:147 as a MermaidParseError whenever the Langium parser for a beta diagram type (info, packet, pie, architecture, gitGraph, eventmodeling, radar, railroad, railroadEbnf, railroadAbnf, railroadPeg, treemap, treeView, wardley, cynefin) reports any lexerErrors or parserErrors. The constructor at parse.ts:152 formats each lexer error as 'Lexer error on line L, column C: msg' and each parser error as 'Parse error on line L, column C: msg', then joins them into 'Parsing failed: <lexerErrors> <parserErrors>'. It is the single unified, typed error surface for every Langium-backed diagram type; the raw ParseResult is exposed on error.result for programmatic inspection.

Source

Thrown at packages/parser/src/parse.ts:147

export async function parse(diagramType: 'treemap', text: string): Promise<Treemap>;
export async function parse(diagramType: 'wardley', text: string): Promise<Wardley>;
export async function parse(diagramType: 'cynefin', text: string): Promise<Cynefin>;

export async function parse<T extends DiagramAST>(
  diagramType: keyof typeof initializers,
  text: string
): Promise<T> {
  const initializer = initializers[diagramType];
  if (!initializer) {
    throw new Error(`Unknown diagram type: ${diagramType}`);
  }
  if (!parsers[diagramType]) {
    await initializer();
  }
  const parser: LangiumParser = parsers[diagramType];
  const result: ParseResult<T> = parser.parse<T>(text);
  if (result.lexerErrors.length > 0 || result.parserErrors.length > 0) {
    throw new MermaidParseError(result);
  }
  return result.value;
}

export class MermaidParseError extends Error {
  constructor(public result: ParseResult<DiagramAST>) {
    const lexerErrors: string = result.lexerErrors
      .map((err) => {
        const line = err.line !== undefined && !isNaN(err.line) ? err.line : '?';
        const column = err.column !== undefined && !isNaN(err.column) ? err.column : '?';
        return `Lexer error on line ${line}, column ${column}: ${err.message}`;
      })
      .join('\n');
    const parserErrors: string = result.parserErrors
      .map((err) => {
        const line =
          err.token.startLine !== undefined && !isNaN(err.token.startLine)
            ? err.token.startLine

View on GitHub (pinned to d93e9c88c0)

Solutions

  1. Read the embedded position in the message (e.g. 'Parse error on line 2, column 3') to locate the offending token.
  2. Catch MermaidParseError and inspect error.result.lexerErrors and error.result.parserErrors for structured detail (messages, tokens, line/column).
  3. Reduce the diagram to a minimal known-good example from the grammar docs, then re-add lines until it breaks to isolate the bad construct.
  4. Confirm the diagramType argument matches a supported key in the initializers map (parse.ts:39) and that the text begins with the expected beta header token.

Example fix

// before
const src = `radar-beta
  axis my-axis my-axis2
  curve c{1,2}`;
await parse('radar', src); // throws MermaidParseError: two identifiers on one axis

// after
const src = `radar-beta
  axis food["Food"], service["Service"]
  curve a["A"]{4,3}`;
await parse('radar', src);
Defensive patterns

Strategy: try-catch

Validate before calling

// Light pre-check only; full grammar validation requires the Langium parser itself.
function preflightLangiumParse(diagramType, text) {
  if (!text || !text.trim()) throw new Error('empty diagram text');
  const known = ['info','packet','pie','architecture','gitGraph','eventmodeling','radar','railroad','railroadEbnf','railroadAbnf','railroadPeg','treemap','treeView','wardley','cynefin'];
  if (!known.includes(diagramType)) throw new Error('unsupported diagramType: ' + diagramType);
}

Type guard

import { MermaidParseError } from '@mermaidjs/parser';
function isMermaidParseError(e: unknown): e is MermaidParseError {
  return e instanceof MermaidParseError;
}

Try / catch

import { parse, MermaidParseError } from '@mermaidjs/parser';
try {
  const ast = await parse('radar', src);
} catch (e) {
  if (e instanceof MermaidParseError) {
    for (const pe of e.result.parserErrors) console.warn('parse', pe.token.startLine + ':' + pe.token.startColumn, pe.message);
    for (const le of e.result.lexerErrors) console.warn('lex', le.line + ':' + le.column, le.message);
    // surface a friendly message to the end user; do not crash the renderer
  } else {
    throw e;
  }
}

Prevention

When it happens

Trigger: Calling parse(diagramType, text) (or the railroad/ebnf/abnf/peg wrappers that also construct MermaidParseError) with text that violates the grammar for that diagramType. After parser.parse(text) returns, any non-empty result.lexerErrors or result.parserErrors (checked at parse.ts:146) triggers the throw. Concrete examples: radar-beta with 'axis my-axis my-axis2' (two identifiers on one axis), 'curve my-curve' with no matching axis entries, or an unlexable token like 'invalid@symbol'. Also thrown if diagramType is valid but the text is structurally incomplete (e.g. radar-beta followed only by 'axis').

Common situations: Copying old jison-era mermaid syntax into a beta diagram that now uses the Langium parser; typos in keywords ('axe' instead of 'axis'); supplying the wrong number of values (curve entry count vs axis count); grammar drift across mermaid versions; feeding user-authored or templated diagram text without validation; passing the wrong diagramType key for the text body.

Related errors


AI-assisted analysis of mermaid-js/mermaid@d93e9c88c0 (2026-08-12). Data as JSON: /api/errors/585a2d5b8da23d60. Report an issue: GitHub.