Mermaid syntax checker
Mermaid syntax checker: find and fix errors in your diagram code
In short
Paste Mermaid code and this page runs Mermaid 11's own parser in your browser, lists every error it finds with the line, the likely cause and the fix, applies the safe fixes for you (quoting labels with brackets, closing an open subgraph or alt, renaming a node called end) and renders the diagram as soon as it is valid. Nothing is uploaded. Below the tool is a reference table of the most common Mermaid errors and what each message means.
Updated · by the ChartCraft team · validates with Mermaid 11
Checker
Runs in your browser — nothing is uploaded. Mermaid (about 2.5 MB) is downloaded from esm.sh on your first keystroke.
Preview (shown when the code is valid)
What does the checker look for?
Two passes. First, fast local checks that do not need Mermaid and can flag several lines at once. Second, Mermaid's own parse(), whose error is decoded into a cause and a fix. Safe fixes are applied automatically and the result is re-parsed; Copy fixed code is only enabled when the fixed text is valid.
| Check | What triggers it | Auto-fix |
|---|---|---|
| Code fences | Text starts with ``` (pasted from Markdown) | Yes — fence lines removed |
| Diagram keyword | First line is not a known keyword, or has the wrong case (Flowchart, SequenceDiagram) | Yes, for case; no for unknown words |
| Comments | A line begins with // or # instead of %% | Yes — rewritten as %% |
| Unclosed blocks | More subgraph / alt / opt / loop / par / critical / break / rect / box lines than end lines | Yes — missing end appended (move it if the block should close earlier) |
Extra end | More end lines than open blocks, or END in capitals | Capitals yes; extra end no |
Reserved word end | A flowchart node whose id is lowercase end | Yes — renamed End |
| Unquoted label characters | ( ) [ ] { } | or " inside a node label | Yes — label wrapped in quotes, inner quotes become #quot; |
| Arrow typos | -- > with a space, or a single-dash -> in a flowchart or class diagram | Yes — arrow rewritten |
| Empty shape | A[] or A() with nothing inside | Yes — placeholder label |
| Message without text | Sequence arrow with no : text | Yes — placeholder text |
Unclosed { | Class body or composite state without } | Yes — } appended |
| Everything else | Mermaid's parse error, mapped to a cause and fix when the pattern is known | No — manual fix with guidance |
What are the most common Mermaid errors and how do I fix them?
Most Mermaid errors come from six habits: unquoted labels with brackets, a block that is never closed, a node named end, a message or relationship without its text, an arrow typed with one dash too few, and a diagram keyword in the wrong case. The table lists the message Mermaid 11 prints for each, what caused it and the fix. Messages are abbreviated: Mermaid prints the full list of expected tokens.
| Mermaid says | Diagram | Cause | Fix |
|---|---|---|---|
No diagram type detected matching given configuration for text | any | The first line is not a diagram keyword: wrong case (Flowchart), a ```mermaid fence, or prose before the keyword. | Start the text with flowchart TD, sequenceDiagram, classDiagram, stateDiagram-v2, erDiagram… exactly in that case. |
Parse error on line N … Expecting 'SQE', 'PE', …, got 'PS' | flowchart | An opening parenthesis inside a square-bracket label: A[Parse JSON (strict)]. The lexer reads ( as a new shape. | Quote the label: A["Parse JSON (strict)"]. Alternatively use HTML entities #40; and #41;. |
Expecting 'SQE', …, got 'SQS' | flowchart | Nested square brackets in a label: A[list [items]]. | Quote the label: A["list [items]"]. |
Expecting 'SQE', 'TAGEND', …, got 'PIPE' | flowchart | A pipe | inside a label; | delimits edge text in flowcharts. | Quote the label, or write #124;. |
Expecting 'SQE', …, got 'STR' | flowchart | A double quote in the middle of an unquoted label: A[He said "hi"]. | Quote the whole label and write inner quotes as #quot;: A["He said #quot;hi#quot;"]. |
Expecting 'TAGEND', 'STR', 'MD_STR', …, got 'SQE' | flowchart | Empty brackets: A[]. | Put a label inside the brackets or drop them. |
Expecting 'AMP', 'COLON', …, 'NODE_STRING', …, got 'end' | flowchart | A node called end; lowercase end is the keyword that closes a subgraph. | Use End, END or finish[End]. The Mermaid docs recommend capitalising it. |
Expecting 'SEMI', 'NEWLINE', …, 'end', …, got 'EOF' | flowchart | A subgraph was opened and the text ended before its end. | Add end on its own line after the last node of the subgraph. |
Expecting 'SEMI', 'NEWLINE', 'EOF', 'AMP', 'START_LINK', 'LINK', …, got 'NODE_STRING' | flowchart | Two identifiers next to each other — usually a node id containing a space (Start here --> B). | Put spaces in a label, not the id: start[Start here] --> B. |
Expecting 'SEMI', 'NEWLINE', …, got 'MINUS' | flowchart | Single-dash arrow A -> B (that is sequence-diagram syntax). | Use -->; also --- line, -.-> dotted, ==> thick. |
Expecting 'LINK', 'UNICODE_TEXT', 'EDGE_TEXT', got 'EOF' | flowchart | A space inside the arrow: A -- > B, so Mermaid sees an edge-text start and no link. | Write the arrow without internal spaces: A --> B. |
Expecting 'AMP', 'COLON', …, got 'EOF' | flowchart | A line ends with an arrow and no target: A -->. | Complete the link with a target node. |
Lexical error on line N. Unrecognized text. | flowchart | A character the lexer cannot place — an invalid direction (flowchart XX), smart quotes “ ” pasted from a document, or a stray symbol. | Use TB, TD, BT, LR or RL; replace smart quotes with straight quotes; delete the character under the ^ marker. |
Expecting 'TXT', got 'NEWLINE' | sequenceDiagram | A message with no text after the arrow: Bob->>Alice. Every message needs : text. | Write Bob-->>Alice: OK. (-> solid line, --> dotted, ->> solid arrow, -->> dotted arrow, -x cross, -) async.) |
Expecting 'SPACE', 'NEWLINE', …, 'end', …, got 'EOF' | sequenceDiagram | An alt, opt, loop, par, critical, break, rect or box block without end. | Close every block with end; nested blocks need one end each. |
Trying to inactivate an inactive participant (X) | sequenceDiagram | A -->>- or deactivate X with no matching ->>+ / activate X before it. | Pair every + with a later - on the same participant, or remove the -. |
Expecting 'STRUCT_STOP', 'MEMBER', got 'EOF_IN_STRUCT' | classDiagram | A class body class A { without its closing }. | Add } after the last attribute or method. |
Expecting 'LINE', 'DOTTED_LINE', got 'ALPHA' | classDiagram | A relation written with one dash (A -> B). | Use two characters: --|> inheritance, --* composition, --o aggregation, --> association, ..> dependency, ..|> realization, -- link. |
Expecting 'COLON', 'STYLE_SEPARATOR', got 'NEWLINE' | erDiagram | A relationship line without a label: CUSTOMER ||--o{ ORDER. | Append : label: CUSTOMER ||--o{ ORDER : places. |
Expecting 'SPACE', 'NL', …, 'STRUCT_STOP', …, got 'EOF' | stateDiagram-v2 | A composite state X { without its }. | Close the composite state with }. |
Expecting token of type 'NUMBER_PIE' but found … | pie | A slice value that is not a number. | Use "Label" : 42; decimals are allowed, text is not. |
Cannot set properties of undefined (setting 'style') | flowchart | linkStyle N refers to a link that does not exist (links are numbered from 0 in source order). | Lower the index, or use linkStyle default. |
How do I read a Mermaid parse error?
A Mermaid parse error has four parts: the line number, the text of that line with earlier lines run together, a ^ marker under the position where parsing stopped, and the list of tokens the parser would have accepted (Expecting) followed by the token it actually found (got). The fault is almost always the character just before the marker, and the got token names it.
Parse error on line 3:
...wchart TDA[Call foo(bar)]-->B
----------------------^
Expecting 'SQE', 'DOUBLECIRCLEEND', 'PE', '-)', 'STADIUMEND', 'SUBROUTINEEND',
'PIPE', 'CYLINDEREND', 'DIAMOND_STOP', 'TAGEND', 'TRAPEND', 'INVTRAPEND',
'UNICODE_TEXT', 'TEXT', 'TAGSTART', got 'PS'
The token names come from Mermaid's grammar files. The ones you will meet most often:
| Token | Meaning |
|---|---|
SQS / SQE | [ / ] — square-bracket shape start / end |
PS / PE | ( / ) — round shape start / end |
DIAMOND_START / DIAMOND_STOP | { / } — decision shape |
PIPE | | — edge-text delimiter |
STR / MD_STR | A double-quoted string / a Markdown string "`…`" |
TEXT / UNICODE_TEXT / NODE_STRING | Plain label text / non-ASCII text / a node id |
LINK / START_LINK / EDGE_TEXT | An arrow such as --> / the start of -- text --> / the text in it |
TAGSTART / TAGEND | < / > (HTML tags such as <br> in labels) |
AMP | & — joins nodes: A & B --> C |
COLON / SEMI | : (class assignment :::, sequence message text) / ; statement separator |
NEWLINE / SPACE / EOF (shown as '1' in some versions) | End of line / whitespace / end of the whole text |
TXT | Sequence diagram message text after the colon |
STRUCT_STOP / EOF_IN_STRUCT | Closing } of a class or composite state / text ended inside one |
ALPHA | A word where the class-diagram parser expected a relation |
Why does a diagram work in one tool and fail in another?
Because every host embeds its own copy of Mermaid. GitHub, GitLab, Obsidian, Notion, VS Code extensions and documentation generators update at different times, and Mermaid adds diagram types and syntax between releases. Code that validates here on Mermaid 11 can fail on a host that still runs Mermaid 10, and the other way round when a host has not caught up with stricter parsing.
| Needs Mermaid 11 | Safe on every version |
|---|---|
A@{ shape: cyl, label: "DB" } — the new shape syntax | Classic shapes: A[(DB)], A{Decision}, A([Terminal]) |
architecture-beta, kanban, packet-beta, radar-beta, treemap-beta | flowchart, sequenceDiagram, classDiagram, stateDiagram-v2, erDiagram, gantt, pie |
--- YAML front-matter with config: | %%{init: { "theme": "dark" }}%% directives |
Markdown strings ["`**bold**`"] (10.x+) | Plain quoted labels ["text"] and <br> line breaks |
Questions
Is this Mermaid syntax checker free, and where does my code go?
It is free and your code never leaves the page: the checker downloads Mermaid 11 from esm.sh once and runs the parser in your browser. There is no upload, no account and no size limit beyond what your browser can render.
Which Mermaid version does the checker use?
The current Mermaid 11 release served by esm.sh (mermaid@11), the same library GitHub, GitLab, Obsidian and most renderers embed — though each of those ships its own version, so a diagram type added in a newer release can fail there and pass here.
Why does the checker show only one error at a time?
Mermaid's parser stops at the first token it cannot handle, so one parse gives one error. The checker adds its own pre-checks (fences, unbalanced blocks, reserved words, comment markers) that can report several lines at once, and re-parses after each auto-fix so the next error surfaces immediately.
What does "Expecting 'SQE', got 'PS'" mean?
The flowchart lexer expected the end of a square-bracket label (SQE = ]) but found an opening parenthesis (PS = (). Your label contains parentheses: quote it — A["Call foo(bar)"]. The token table on this page decodes the other names.
Can I use "end" as a node name in a Mermaid flowchart?
Not in lowercase: end is the keyword that closes a subgraph, and the Mermaid docs warn it breaks the diagram. Use End, END, end_ or an id with a label such as finish[End].
How do I put parentheses, brackets or quotes in a Mermaid label?
Wrap the label in double quotes: A["Parse (strict)"]. For a literal double quote inside a quoted label use #quot;; any character can be written as a numeric entity such as #40; for ( and #91; for [.
Why does my diagram render on GitHub but fail here (or the other way round)?
Different Mermaid versions. Newer diagram types (architecture-beta, kanban, packet-beta) and newer shape syntax (A@{ shape: … }) need Mermaid 11; stricter label parsing was also introduced over time. Check the version your platform runs, and keep labels quoted — that is valid everywhere.
Does the checker fix the diagram for me?
It applies the fixes that cannot change your meaning — quoting a label, closing an open block, renaming a node called end, fixing a mistyped arrow, removing code fences — and only offers the result when the fixed text parses. Structural problems (an arrow into a subgraph keyword, a missing participant) are explained but left to you.