Skip to main content

Rendering Diagnostics

When a payload contains a typo in a style property, an invalid value, a missing asset, or text no available font can render, the engine degrades gracefully and continues — the render succeeds, but the affected bit is gone. Invisible, unless someone is reading the server's log warnings.

The diagnostics opt-in surfaces every such event inside the rendered document itself. Same pattern the barcode encoder already uses for invalid payloads ([barcode error: …] placeholders inline) — extended to styles, assets, fonts and canvas commands.

Live example​

A fixture with seven intentional failure cases — a style typo, an invalid value, an undefined style reference, a missing image, pasted text without font coverage, a malformed canvas command, and inline shortcode typos. Markers appear below each case; the appendix on the last page aggregates them.

How to enable​

Add a diagnostics block at the document root:

{
"document": {
"diagnostics": {
"showInDocument": "appendix",
"minLevel": "warning"
},
"content": [ ... ]
}
}
PropertyTypeDefaultDescription
showInDocumentstring"off"How to surface diagnostics: off (silent-drop behavior, log warnings only), appendix (aggregated table at end of document), inline (marker paragraphs directly below the element that raised each issue), both (inline markers + appendix).
minLevelstring"warning"Lowest severity to include: info (benign normalizations like case-folding), warning (silent drops), error (hard failures the renderer caught and skipped).

The default off is genuinely free: no collection work happens and the render carries no diagnostics overhead. Opting in always produces complete diagnostics — nothing else needs to be configured.

What gets captured​

Every content-affecting failure in the renderer flows through this surface automatically — no per-site instrumentation. Coverage includes:

  • Style typos — fontSizr: 14 instead of fontSize. Captured as warning.
  • Invalid values — textAlign: "sideways", strokeLinecap: "wedge", unparseable colors. Captured as warning.
  • References to undefined styles — { "p": "...", "style": "doesNotExist" }. Captured as warning.
  • Missing or unresolved assets — an image path that resolves to nothing (block, inline [image], or canvas), a font family file that fails to load. Captured as warning.
  • Text without font coverage — content in a language no available font can render (for example pasted text in a script outside the built-in coverage and any declared fonts). The message names the script and points to the document's fonts section.
  • Canvas command failures — malformed SVG path data, unknown barcode symbology, commands missing required values.
  • Inline shortcode values — [font, X] naming an undeclared family, unparseable [fontcolor]/[mark] colors, invalid [fontsize]/[letterspacing]/[align] values. Captured as warning; the tag and the rejected value are named.

The collector dedupes each distinct failure: a style with a typo applied to 100 paragraphs — or one missing font hit by 50 text runs — produces ONE entry, not 100. Severity is escalated if the same source reports a stronger issue later, so the appendix reflects the worst case.

Appendix format​

When showInDocument is appendix or both, the renderer appends a "Rendering Diagnostics" section at the end of the document with a table:

SeveritySourcePropertyMessage
WARNINGintentionalTypofontSizrUnrecognized style property 'fontSizr' on style 'intentionalTypo'.
WARNINGstyleThatDoesNotExistStyle 'styleThatDoesNotExist' is not defined in the document's styles section.
WARNING(engine)missing/thermal-plot.pngImage asset 'missing/thermal-plot.png' could not be resolved; the image was skipped.
WARNING(engine)OtherNo available font can render Other text — "Բարեւ աշխարհ…" will be missing from the output. Add a font that covers this script to the document's fonts section.

Severity is color-coded: warnings in dark goldenrod, errors in firebrick, info in slate gray.

Inline markers​

When showInDocument is inline or both, a marker paragraph is emitted directly below the element that raised each issue — whether the issue came from a named style or from the engine (a missing image, uncovered text, a canvas command). Elements don't need a style for their failures to surface:

⚠ intentionalTypo: fontSizr — Unrecognized style property 'fontSizr' on style 'intentionalTypo'.

Each distinct failure is marked once (dedupe), in the natural flow position, so authors see WHERE the problem happened.

Severity levels​

LevelWhen emittedExample
infoBenign normalization — case-folded enum value, deprecated alias resolved, optional section absent.textAlign: "CENTER" accepted and normalized to "center".
warningSilent drop — property dropped or content substituted with a fallback. Renderer continued.Unknown property, invalid value, unresolved asset, uncovered text.
errorHard failure the renderer caught. Element skipped, render continued.Required asset missing, malformed barcode payload.

The default minLevel is warning so info-level normalizations stay quiet unless explicitly enabled.

Nothing else changes​

Enabling diagnostics only adds the markers and the appendix — the rest of the render is identical, and server-side logging continues exactly as before. It is an additional surface for authors, not a replacement for operational logging.

  • Authoring environments — IDE / sandbox renders where authors should see their typos.
  • Pre-production validation — CI render of every template with showInDocument: "appendix" and a non-empty appendix flagged as a CI failure.
  • Customer-portal previews — let template authors debug their own definitions without log-diving.
  • Production renders for end-customers — the appendix is an authoring affordance, not customer-facing content. Default off is the right setting for delivered documents.

Format parity​

Both PDF and DOCX render the same diagnostics shape with the same inline-marker and appendix behavior, and the markers and appendix are composed through each format's regular content pipeline — so their styling matches body content in both outputs.