[KongchangAI]
· 2 min read· 1,171 words

The Mystery of Vanishing SVG Text: The Font Dependency Trap in Mermaid Rendering Services

The Mystery of Vanishing SVG Text: The Font Dependency Trap in Mermaid Rendering Services

Mermaid SVG text disappears because of missing fonts; fix by installing fonts and adjusting default output.

A developer built a Mermaid-to-image API. PNG output worked, but SVG appeared blank on Slack, Discord, and similar platforms. The issue: Mermaid's SVG keeps text as text and specifies fonts absent from the server. Browsers fall back to other fonts, but other consumers don't, making text invisible. The fix was installing fonts-dejavu-core in the Dockerfile and explicitly setting the font stack, plus switching the default output to PNG and making SVG an opt-in with warnings. The article stresses that rendering APIs must be tested in real consumption environments, not just in dev browsers, since browser fault tolerance masks problems.

Introduction: When a "Valid SVG" Becomes an "Invisible Chart"

A developer built a Mermaid-to-image API service that converts flowcharts, sequence diagrams, class diagrams, and more into PNG or SVG format, returned as base64-encoded data so AI agents can generate shareable images. Everything worked fine during testing, but real users sent back screenshots: where the chart was supposed to appear, there was only blank space.

The problem only appeared with SVG output. PNG worked perfectly. The SVG files themselves were valid XML, but opening them in a browser showed nothing at all. After investigation, the culprit emerged: Mermaid's SVG output embeds text as <text> elements and specifies a font that doesn't exist on the rendering server. Browsers fall back to alternative fonts, so you can see the text; but most consumers like Slack, Discord, and GitHub previews don't fall back — they faithfully honor the missing font, and the result is that nothing renders. The text is right there in the DOM, just "invisible."

Mermaid rendering problem illustration

Root Cause: Two Contracts of Font Dependency

The Essential Difference Between PNG and SVG

The developer boiled the problem down to an overlooked contract difference: when rendering images server-side, you're not just delivering pixels — you're also delivering font dependencies.

PNG rasterizes text into pixels at render time, so the font only needs to exist on your server. SVG keeps text as text, which means the font must exist on every device that displays it. This sounds like a detail, but it directly determines whether the output is visible in the real world.

SVG text rendering and font fallback mechanisms

SVG is an XML-based vector graphics format whose text is described through <text> elements and references fonts via the font-family attribute. Unlike bitmaps, SVG itself does not contain font data (unless you use @font-face embedding or convert text to paths), so rendering results depend heavily on the display environment. Browsers typically implement font fallback: when the specified font is missing, they try each font in the font-family list in order and ultimately use the system default, ensuring text visibility. But many non-browser consumers (such as chat app previews, Markdown renderers on code hosting platforms, and email clients) often use simplified SVG rendering engines for performance or security reasons, which may not support font fallback and may even ignore text elements with missing fonts entirely. This is why the same SVG looks fine in a browser but "invisible" on other platforms. Understanding this difference helps you proactively choose more reliable output strategies when designing server-side rendering APIs.

The Specific Triggering Conditions

The problem was hidden because the developer's environment masked it. The rendering server used headless Chromium with the --font-render-hinting=none flag, running in a minimal container image that had no fonts installed at all. Meanwhile, Mermaid defaults font-family to "trebuchet ms", verdana, sans-serif, none of which exist on the server.

When testing in a browser, the browser automatically substituted fonts and everything looked fine. But once the SVG file was sent to Slack, Discord, GitHub comments, Notion, or email clients, those platforms did not perform font fallback, and text with missing fonts was simply invisible. The developer spent three days producing charts that "nobody could see."

Headless browsers and font rendering flags

Headless Chromium is a browser mode that runs Chromium without a graphical interface, commonly used for server-side automated rendering, screenshots, and PDF generation. It loads system fonts by default, but container images often omit font packages to reduce size. The --font-render-hinting=none flag disables font hinting to make rendering results more consistent across platforms, but it does not solve missing fonts. When the font specified by a page doesn't exist, headless browsers may fall back to a default font or simply not render the text, depending on the version and configuration. Developers easily pass tests in their local development environment (which usually has a rich set of fonts) but encounter missing text after deploying to a stripped-down container. Therefore, explicitly installing the required fonts in the container and specifying a font stack that actually exists in the rendering configuration are key steps to ensuring output reliability.

Fix and Engineering Lessons

A Two-Line Dockerfile Fix

The solution turned out to be surprisingly simple: install fonts-dejavu-core in the Dockerfile, and set Mermaid's fontFamily to a font stack that actually exists on the server (DejaVu Sans, sans-serif) instead of the default "trebuchet ms", verdana, sans-serif. After the change, the SVG output rendered consistently in Slack, Discord, Notion, GitHub comments, and email clients.

fonts-dejavu-core and font stack design

fonts-dejavu-core is a basic font package in Debian/Ubuntu-based Linux distributions. It includes fonts such as DejaVu Sans, DejaVu Serif, and DejaVu Sans Mono, covering Latin, Greek, Cyrillic, and common symbols. It is small, open-source, and often used as the minimal font set for container environments. After installation, you need to explicitly set fontFamily to "DejaVu Sans, sans-serif" in the Mermaid configuration to ensure the renderer prioritizes the installed font, with generic sans-serif as the final fallback. This way, the fonts referenced in the font-family attribute of the generated SVG are more likely to be available on the server and most consumers, reducing the risk of "invisible text." For services that need multilingual support, you should also consider installing more comprehensive font packages (such as fonts-noto-cjk) and documenting the font dependencies.

Adjusting Design Decisions

After the fix, the developer changed the default output for new users to PNG, made SVG an opt-in feature, and added warnings to the documentation. This decision is worth emulating: for charts that need to be widely shared, PNG's "font self-containment" reduces cross-platform risk; SVG is more flexible, but users must be clearly informed of its font dependencies.

Rethinking Testing Strategy

The article concludes with a universally applicable piece of advice: if you're building any image or chart rendering API, test where the output is actually consumed, not just in the browser on your dev machine. Browsers' fault tolerance masks problems, while real consumers are often stricter. A "valid SVG" and a "visible chart" are not the same thing.

Implications for AI Agent Tool Development

This case has direct relevance to the rapidly growing AI agent tool ecosystem. When AI agents generate charts, reports, or visualizations and deliver them to users, the choice of output format directly affects usability. The developer ultimately packaged the service as x402.freeq.one, supporting flowcharts, sequence diagrams, class diagrams, and Gantt charts, returning base64 data for PNG or SVG in a single call.

For teams building similar services, there are three actionable takeaways:

  • Default to PNG unless the user explicitly needs vector editability.
  • Strictly install fonts and explicitly specify the font stack in the rendering configuration.
  • Validate in the target consumption environment, including Slack, Discord, GitHub, and other platforms in your testing scope.

Fonts may seem like an end-of-pipeline detail, but they actually determine whether server-generated images can truly be seen.

One-line Summary

Mermaid-to-SVG produces invisible text due to missing fonts; the fix requires installing fonts and adjusting default output.

#Mermaid#SVG rendering#font dependency#server-side rendering#font fallback#Docker#headless Chromium
Share:

Related articles