Skip to main content

Rendering Diagnostics

When a payload contains a typo in a style property, an invalid enum value, or a reference to a style that isn't defined, the rendering engine silently drops the offending bit and continues. The render succeeds, but the broken declaration is gone — invisible unless someone is reading the engine's log warnings.

The diagnostics opt-in surfaces every such silent-drop event inside the rendered document itself. Same pattern the barcode encoder already uses for invalid payloads ([barcode error: …] placeholders inline) — extended to style properties, missing assets, and unresolved references.

Live example

A fixture with intentional typos. The appendix on the last page lists every dropped property.

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 (current silent-drop behavior, log warnings only), appendix (aggregated table at end of document), inline (marker paragraphs at first use of each affected style), 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).

What gets captured

Every silent-drop site in the renderer flows through this surface automatically — no per-site instrumentation. Today's coverage:

  • Style typosfontsizr: 14 instead of fontSize. Captured as warning.
  • Invalid enum valuestextAlign: "sideways", strokeLinecap: "wedge". Captured as warning.
  • References to undefined styles{ "p": "...", "style": "doesNotExist" }. Captured as warning.
  • Missing or unresolved assets — referenced font, image, or barcode payload that fails to load. Captured as warning or error depending on the site.

The collector dedupes by (source, property): a style with a typo applied to 100 paragraphs produces ONE entry, not 100. Severity is escalated if the same source reports a stronger issue later — 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'.
WARNINGintentionalEnumtextAlignUnsupported textAlign 'sideways' (expected left/center/right/justified).
WARNINGstyleThatDoesNotExist(style)Style with key 'styleThatDoesNotExist' not found or has no properties.

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 at the first use of each style with diagnostics:

⚠ intentionalTypo: unknown 'fontsizr'; invalid textAlign 'sideways'

Subsequent uses of the same style don't re-emit (dedupe). The marker sits in the natural flow position so authors see WHERE the broken style was applied.

Severity levels

LevelWhen emittedExample
infoBenign normalization — case-folded enum value, deprecated alias resolved.textAlign: "CENTER" accepted and normalized to "center".
warningSilent drop — property dropped or substituted with a fallback. Renderer continued.Unknown property, invalid enum, missing optional asset.
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.

Logging is preserved

Enabling diagnostics does not silence the existing engine log warnings. They continue to flow through the caller-supplied ILogger exactly as before — diagnostics is an additional surface, not a replacement. The collector is fed by intercepting log events at the logger level (DiagnosticsCapturingLogger), so engine code and external callers see no behavior change.

  • 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 + appendix output. The two render pipelines share the RenderDiagnostics collector and DiagnosticsCapturingLogger from Documentors.Core.Diagnostics, then each format's renderer composes the appendix and inline markers through its native content builder (ContentElementBuilder for PDF, ContentBuilder for DOCX) so styling matches body content in both outputs.