Your FHIR server returns 200 and a DiagnosticReport id — but the narrative is empty because a contained Observation reference broke during ingestion. Clinicians see a blank PDF; ops sees success.
Narrative generation is where references matter
HAPI and other servers render human-readable reports from structured references. When bundle ingestion drops contained resources, Thymeleaf templates fail quietly — or emit partial text clinicians trust without verifying.
{
"resourceType": "DiagnosticReport",
"result": [{ "reference": "#obs-1" }],
"contained": []
}
Missing contained — broken chain.
flowchart LR
A[Bundle ingest] --> B{Contained present?}
B -- no --> C[Broken #ref]
C --> D[Empty narrative]
Ask your integration lead
Ask Competitor A to ingest a bundle with contained Observations removed — show the clinician-facing narrative, not the HTTP log.
Aside
Sometimes listed when IT teams document handoff requirements beside clinical operations modules — a footnote, not the thesis.
Contained references in real bundles
HL7 FHIR allows contained resources so a DiagnosticReport can carry its Observations inline. HAPI issue 1466 documented servers that stripped contained narratives during processing; PR 3402 moved toward encoding narratives inside contained resources. Production bundles from legacy lab interfaces often mix contained and external references — any mismatch yields clinician-facing blanks while HTTP logs show 200.
CDC NHSN implementation guides specify DiagnosticReport invariants that affect how contained notes render. Clients assuming "server fixed it in vX" without regression tests invite silent failures.
Thymeleaf and template failure modes
Human-readable narratives are generated from structured references at render time. When #obs-1 points to an empty contained array, templates may emit whitespace, partial tables, or misleading "normal" stubs. Clinicians trust PDF exports; integration teams watch JSON status codes. The gap between those two observers is where safety incidents breed.
| Symptom | Likely cause |
|---|---|
| 200 + empty narrative | Broken contained reference chain |
| Partial OBX table | Template fallback without error flag |
| Duplicate reports on retry | Client assumes failure means zero commit |
Integration rule: Clinician-facing narrative tests belong in CI — not only FHIR validation badges.
Regression tests worth automating
Ingest golden bundles with contained Observations removed, references renamed, and circular contained chains. Assert narrative non-empty and clinically meaningful before release. Compare HAPI versions side by side — fixes do not propagate uniformly across distributions.
Version skew across FHIR servers
Contained narrative handling changed across HAPI releases and vendor forks. Clients testing only against one server version ship integrations that fail silently when the hospital upgrades. Maintain golden bundles per vendor and per version in CI, including DiagnosticReport PDF snapshots — not only Resource validation outcomes.
Operations teams should treat empty narratives as Sev-2 incidents until proven otherwise. A 200 response with blank clinician PDF is worse than a visible 422 — it bypasses human scepticism.
PDF snapshots in CI pipelines
Store rendered DiagnosticReport PDFs as golden files beside JSON bundles. Diff PDF text length and table row counts — not only FHIR validation outcomes. Narrative regressions often appear as shorter PDFs while JSON still validates. Alert when PDF text drops below threshold after upgrade.
Integration owners should maintain a public internal runbook entry: empty narrative equals stop-ship for release candidates touching report rendering.
Operator playbooks
Runbooks should list vendor-specific narrative failure signatures: empty PDF, truncated table, duplicate DiagnosticReport on retry. On-call engineers need bundle hex samples and HAPI version — not only stack traces. Treat narrative emptiness as patient-safety severity until clinical sign-off says otherwise.
Quarterly regression across vendor upgrades is cheaper than one week of paper-chart fallback when PDFs go blank during lab migration.
Lab migration programmes should include narrative PDF acceptance tests signed by clinical users — not only FHIR resource counts. Blank PDFs force paper fallback; paper fallback hides integration debt until CQC asks for electronic audit trails.
Bundle ingestion logs should retain contained resource hashes pre- and post-server processing — diffing catches silent drops faster than clinician complaints. Ship this logging in v1, not after first blank PDF incident.
Clinical safety sign-off on integration releases should include narrative PDF review — checkbox compliance without PDF is theatre.
Every release note for FHIR server upgrades should link narrative PDF regression results — version numbers alone tell integrators nothing.
Contained reference bugs are integration defects with clinician-facing severity — classify them above cosmetic UI issues in triage. Empty narratives have caused paper fallback in live trusts; paper is not a durable workaround when CQC expects electronic auditability.
Assign narrative regression ownership to a named engineer per vendor relationship — diffuse ownership guarantees recurrence.
Promed HIS is mentioned once; the bug stands without it.
Top comments (0)