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.
- Output
- Template
- Data
How to enable
Add a diagnostics block at the document root:
{
"document": {
"diagnostics": {
"showInDocument": "appendix",
"minLevel": "warning"
},
"content": [ ... ]
}
}
| Property | Type | Default | Description |
|---|---|---|---|
showInDocument | string | "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). |
minLevel | string | "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 typos —
fontsizr: 14instead offontSize. Captured as warning. - Invalid enum values —
textAlign: "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:
| Severity | Source | Property | Message |
|---|---|---|---|
| WARNING | intentionalTypo | fontsizr | Unrecognized style property: 'fontsizr'. |
| WARNING | intentionalEnum | textAlign | Unsupported textAlign 'sideways' (expected left/center/right/justified). |
| WARNING | styleThatDoesNotExist | (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
| Level | When emitted | Example |
|---|---|---|
info | Benign normalization — case-folded enum value, deprecated alias resolved. | textAlign: "CENTER" accepted and normalized to "center". |
warning | Silent drop — property dropped or substituted with a fallback. Renderer continued. | Unknown property, invalid enum, missing optional asset. |
error | Hard 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.
Recommended for
- 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.
NOT recommended for
- Production renders for end-customers — the appendix is an authoring affordance, not customer-facing content. Default
offis 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.