A rendering job came through my diagram API last month: a flowchart for a deployment runbook, one node labeled build (x86). Unquoted parentheses inside square brackets are a classic Mermaid parse trap, and this diagram tripped it. What surprised me wasn't the failure — it was that my API answered 200 OK with 40 KB of PNG and the job marked done.
I opened the image. It was a tidy little box that said "Syntax error in text". Mermaid doesn't throw on bad syntax during render; it draws the parser's complaint as if it were a diagram. Same theme, same fonts, same background. At thumbnail size in a report it looked like any other node. Downstream, nobody questioned it — the runbook briefly documented a build step for a box reading "Syntax error in text".
The fix was to stop trusting render() as validation. Mermaid's parse() call (async since v10) throws a ParseError before any pixels exist. The endpoint now parses first, catches, and returns a 422 with the parser's message and the offending line where I can isolate it. Render only runs after parse agrees the diagram is real. I also kept a belt-and-suspenders sniff on the rendered SVG text for Mermaid's known error strings, because the library has more than one flavor of built-in error art — there's a distinct one for unknown diagram types.
The broader lesson: libraries that produce visual output fail visually, and the library's success is not your API's success. Any wrapper around a drawing library needs its own validation layer, because the library will happily serialize its own error message into whatever format you asked for. A 200 with a plausible-looking payload is the hardest failure mode to debug — nothing crashes, the logs are clean, and the damage only shows up when a human actually reads the output.
I packaged the fixed flow as the renderer at https://x402.freeq.one/tools/mermaid.html — parse-gated, PNG or SVG out, base64-encoded. An agent can POST a flowchart and get an image back without standing up a headless browser; and if the syntax is broken, it gets an error, not a picture of one.
Top comments (0)