How to Fix Mermaid "got 'PS'" Parse Errors (Parentheses in Labels)
Mermaid failing with "got 'PS'"? The cause is a parenthesis in a node label. Quote the label, or use HTML entities. Before/after examples inside.
If your Mermaid diagram fails with Parse error ... Expecting 'SQE', 'PE', ... got 'PS', the cause is almost always a parenthesis inside a node label. Mermaid uses ( and ) to define node shapes — A(text) is a rounded box — so when it meets a stray ( inside a label it was not expecting, it reports the unexpected PS (paren-start) token. The fix is to quote the label. Here is the why and the how.
Where this shows up
Mermaid renders diagrams in GitHub and GitLab Markdown, Notion, Obsidian, and most docs generators. The parser is the same everywhere, so the same label with a parenthesis fails identically whether you are in a README or the live editor. The fix below is portable across all of them.
Why the error happens
In a flowchart, the characters around a node's text choose its shape:
A[Square]
B(Rounded)
C((Circle))
D{Diamond}
The parser reads ( as "a rounded-shape label starts here." So a label like this:
A[Deploy (production)]
confuses it: it is already inside [...], then hits (, and throws Expecting ... got 'PS'. The same thing happens with a ( in an edge label or anywhere the grammar was not expecting a shape delimiter.
The fix: quote the label
Wrap the label text in double quotes. Everything inside the quotes is treated as literal text, parentheses included:
A["Deploy (production)"]
That one change resolves the overwhelming majority of "got 'PS'" errors. It works for every node shape:
A["Build (CI)"]
B("Release (tagged)")
C{"Approved? (manual)"}
When quotes are not enough: HTML entities
Quotes fix parentheses. If you also need characters that Mermaid treats specially even inside quotes — or you are on an older renderer that chokes on them — use HTML numeric entities in the label:
A["Deploy #40;production#41;"]
#40; is ( and #41; is ). Other handy ones: #35; for #, #59; for ;, and #quot; for a literal double quote. Entities are the escape hatch when quoting alone still breaks.
Quick before/after
Broken:
flowchart TD
A[Start] --> B[Run tests (unit)]
B --> C[Deploy (prod)]
Fixed:
flowchart TD
A[Start] --> B["Run tests (unit)"]
B --> C["Deploy (prod)"]
A checklist for "got 'PS'" and its cousins
The same class of error shows up with other unexpected tokens (got 'PE', got 'STR'). The root cause is usually one of these:
- Parentheses in a label → quote the label.
- Square brackets, braces, or pipes (
[,],{,},|) in a label → quote the label; use entities if it still breaks. - A colon or semicolon where Mermaid expected a keyword → quote or entity-encode it.
- A stray quote inside a quoted label → encode it as
#quot;.
Work label by label. Quote first; reach for entities only when a specific character survives the quotes.
Why this bites so often
Diagram labels are written by humans describing real systems, and real systems have names like "Auth service (v2)" or "Retry (max 3)". Parentheses are natural in prose and illegal as bare label text in Mermaid. Getting into the habit of quoting any label that contains punctuation saves you from re-debugging the same parse error every time you add a node.
Line breaks and other markup in labels
Once a label is quoted, you can add a line break inside it with the HTML tag <br>:
A["Deploy to prod<br>(manual approval)"]
A few HTML tags are allowed inside quoted labels, but a bare < or > used as plain text can trigger its own parse error. If you need literal angle brackets, encode them as #lt; and #gt;, the same way you encode parentheses.
Read the line number, then bisect
Mermaid's error usually names the line and the token it choked on — start there, not at the top of the diagram. If the message is vague or the diagram is large, comment out (with %%) or delete half the nodes, re-render, and see whether the error moves. A couple of rounds of that narrows a stubborn "got 'PS'" down to the exact offending label far faster than staring at the whole graph.
Test the fix fast
The quickest way to confirm a fix is the Mermaid Live Editor at mermaid.live: paste the diagram and it re-renders on every keystroke, showing the error and its line inline. Fix the label, watch the error clear, then copy the working source back into your README or docs — that beats committing and waiting for GitHub to re-render just to see whether the parenthesis is happy now.
Next steps
If you generate diagrams with an AI assistant, add a one-line instruction to always quote labels containing punctuation — it removes this failure mode entirely. For assistant setups that encode conventions like this, browse the skills catalog or the development category. And if you keep a personal cheat sheet of fixes like this, our blog collects more of them.
Related Articles
Codex Skills: Install, Use, and the Best Picks
What Codex skills are (a folder with a SKILL.md), how to install one in ~/.agents/skills, how Codex invokes them, and where to find the best picks.
adb shell am force-stop: Stop Android Apps from the Command Line
Use adb shell am force-stop to kill an Android app without deleting its data — and how it differs from pm clear and am kill, with a quick reference.
Cursor Skills: The Complete Guide (List, Examples, and Skills vs Rules)
Cursor has native Agent Skills (SKILL.md) since v2.4: how to create and invoke them, where they live, and how skills differ from .mdc rules.