FHIR implementers, interoperability leads, and partner diligence teams
How to validate an ABDM FHIR DocumentBundle
A reproducible walkthrough for checking an ABDM FHIR R4 DocumentBundle against NRCeS 6.5.0, separating profile errors, terminology gaps, and proof limits.
What this guide delivers
Run the same bounded checks as public CI and know exactly what a green result establishes.
Pin the specification, package, fixture, and validator first
The current published NRCeS guide identifies ndhm.in#6.5.0 as an active release based on FHIR R4 4.0.1. Its DocumentBundle profile defines the minimum expectations for a document Bundle and the contained clinical-document context.
A reproducible run should record that package version, the fixture revision and digest, the validator version and digest, and the terminology mode. MedicalRecords.in currently declares six independently synthetic fixtures, including document-envelope-only DiagnosticReportRecord, DischargeSummaryRecord, and ImmunizationRecord examples. Retained exact public validation evidence covers all six at implementation commit 8628210.[1][2][4][9][10]
python3 scripts/validate_fhir_fixture_manifest.pyExpected deterministic result
FHIR fixture manifest passed: 6 declared fixtures. Any undeclared JSON fixture, live-looking ABDM identifier, profile drift, or missing non-claim makes this step fail.
Run the official validator against the pinned NRCeS package
Use Java 21 or later and a validator_cli.jar whose version and SHA-256 digest you have checked. The repository wrapper loads FHIR 4.0.1 and ndhm.in#6.5.0, disables network terminology during the profile-and-structure phase, enables security checks, and retains one OperationOutcome per fixture.
HL7 describes validation as covering structure, cardinality, value domains, bindings, invariants, and profiles, while also warning that computable validation cannot prove every narrative or business rule. Keep that distinction visible when reporting the result.[3][5]
- Expected validator CLI version: 6.8.1
- Expected validator JAR SHA-256: 7d05b31196557a8ed2748d3c8a1646deba9b6600f5b6946be598949bd11eefe2
- Expected FHIR version: 4.0.1
- Expected implementation package: ndhm.in#6.5.0
- Do not put production records or real identifiers into a public validator or this synthetic evidence workflow.
FHIR_VALIDATOR_JAR=/absolute/path/to/validator_cli.jar \
bash scripts/validate_fhir.shRead the machine outcome instead of trusting one exit code
The Java process can report offline terminology lookup errors even when profile structure is otherwise valid. The repository does not ignore those errors wholesale: it accepts only the exact expression-and-code pairs declared for that fixture, writes a normalized summary, and fails on every other error or fatal issue.
In retained public evidence, all six declared fixtures report profile-structure-pass with zero blocking issues. Each fixture’s declared MIME lookups remain visibly deferred to the separate networked terminology gate, where every exact fixture reports terminology-pass and both invalid controls are rejected.[5][7][8]
python3 -m json.tool fhir/validation/health-document-record-validation-summary.json
python3 -m json.tool fhir/validation/health-document-record-operation-outcome.jsonFail-closed rule
A message is deferrable only when its severity, terminology source, validator message ID, FHIR expression, and expected MIME code all match the fixture manifest. New or broader errors block the run.
Validate every explicit code, language, and media type separately
The second gate inventories every explicit external Coding, CodeableConcept, language, and MIME value in each exact fixture. It uses certificate-verified stateless FHIR terminology operations, pins the SNOMED CT International edition used by the evidence, and requires invalid SNOMED and MIME controls to be rejected.
This command makes network requests to tx.fhir.org. Run it only with synthetic fixtures, review the service boundary before using another server, and retain the summary beside the fixture digest.[3][6][7][8]
- Expected verdict for each declared fixture: terminology-pass
- Expected negative controls: two rejected invalid values
- Expected fixture SHA-256: an exact match with the bytes that were validated
- Open boundary: no India-extension or broader health-information-type terminology evidence is implied.
while IFS=$'\t' read -r fixture_id fixture_path; do
python3 scripts/validate_fhir_terminology.py \
"${fixture_path}" \
--fixture-id "${fixture_id}" \
--summary "fhir/validation/${fixture_id}-terminology-summary.json"
done < <(python3 scripts/validate_fhir_fixture_manifest.py --list-tsv)Fix the boundary that failed; do not suppress the symptom
Start with the first blocking expression and compare it with both the differential profile and the full Bundle context. A valid standalone resource can still fail when its profile, slice, reference, or document position is wrong.
If terminology fails, verify the system, version, code, display, value-set binding, and server capability separately. Do not convert a service outage or unsupported code system into a permanent pass rule.[2][3]
- 1Confirm Bundle.type is document and Bundle.meta.profile names the published DocumentBundle canonical.
- 2Confirm the first entry is the profiled Composition and every fullUrl reference resolves inside the Bundle.
- 3Compare the Composition profile with the intended health-information type and package version.
- 4Resolve each blocking cardinality, invariant, slice, or reference error before reviewing warnings.
- 5Run terminology independently and preserve both the positive checks and rejected negative controls.
- 6Add a fixture-specific deferral only when the offline error is exact, understood, separately validated, reviewed, and regression-tested.
Bind the claim to the exact source, run, artifact, and limits
For implementation commit 8628210, the public CI run retained the manifest, six OperationOutcomes, six profile summaries, and six terminology summaries. The exact artifact reports zero blocking profile-and-structure issues, terminology-pass, and two rejected terminology controls for every declared fixture.
That evidence proves only those synthetic examples against those named checks. It does not prove live ABDM exchange, M1/M2/M3 sandbox completion, certification, production mapping, consent enforcement, clinical validity, legal compliance, approval, endorsement, or fitness for patient care.[4][7][8]
git rev-parse HEAD
python3 scripts/validate_fhir_fixture_manifest.py --list-tsvA green validator is a bounded engineering result
Pair it with workflow, identity, consent, security, clinical-safety, deployment, and external-assurance evidence before making a commercial or production claim.
Sources and evidence boundary
- [1]ABDM FHIR Implementation Guide 6.5.0 — National Resource Centre for EHR Standards
- [2]NRCeS DocumentBundle profile 6.5.0 — National Resource Centre for EHR Standards
- [3]Validating FHIR R4 resources — HL7 International
- [4]Supported synthetic fixture manifest at 8628210 — MedicalRecords.in repository
- [5]Pinned official-validator wrapper at 8628210 — MedicalRecords.in repository
- [6]Exact-fixture terminology gate at 8628210 — MedicalRecords.in repository
- [7]Exact public FHIR conformance CI run for 8628210 — MedicalRecords.in GitHub Actions
- [8]Retained six-fixture official-validator artifact for 8628210 — MedicalRecords.in GitHub Actions
- [9]NRCeS DischargeSummaryRecord profile 6.5.0 — National Resource Centre for EHR Standards
- [10]NRCeS ImmunizationRecord profile 6.5.0 — National Resource Centre for EHR Standards
Sources support the specific statements linked above. Their inclusion does not imply endorsement of MedicalRecords.in. Product evidence is labelled separately in the Trust Center. Report a correction.
Put the guide to work