My Mermaid renderer drew tofu boxes instead of labels — the container had no fonts installed
Agents write Mermaid constantly — sequence diagrams for API designs, flowcharts for release flows — but there's rarely anything on the other end that can display it. That gap is why I built a renderer: POST diagram synta
Agents write Mermaid constantly — sequence diagrams for API designs, flowcharts for release flows — but there's rarely anything on the other end that can display it. That gap is why I built a renderer: POST diagram syntax, get back a base64 PNG or SVG. I ended up packaging it as the Mermaid Diagram Renderer API (https://x402.freeq.one/tools/mermaid.html) so I could stop maintaining the render stack myself.
The first version looked fine in my tests and broke immediately on real input. A long sequence diagram came back with intact boxes, arrows, and lifelines — and where every label should be, rows of empty rectangles. Tofu glyphs, top to bottom.
The cause was my Dockerfile. I'd used a slim base image and installed headless Chromium for rendering, but no font packages. A browser without fonts can't rasterize text at all, so the renderer "worked" while drawing nothing legible.
The subtle part: Mermaid sizes nodes by measuring text width before drawing it. With no usable font, those measurements collapse, so node boxes shrank to near-nothing and arrows crossed over each other. Even with a fallback font, layouts were subtly wrong because the measurement font didn't match the rasterization font. A diagram is measured typography, not just shapes on a canvas.
The fix: fonts-liberation plus Noto, a fc-cache -f layer step, and a pinned font-family in the render options so measurement and rasterization always share one face. I also added a canary — a tiny flowchart with a known label — and compare its pixel histogram on every deploy. Label pixels present, or the deploy halts.
The lesson generalizes beyond Mermaid: any headless-browser rendering in a container needs fonts as a first-class dependency, and smoke tests that only assert "an image came back and it's non-empty" will happily pass while producing garbage. Verify the content pixels exist, not the file.
Originally published by Dev.to AI. Aggregated on AIWithGhost for educational purposes — full credit and traffic to the original publisher.