Bundle Validation in CI: Catching Bad Payloads Before Production

Editorial illustration in woodblock-print style depicting a CI pipeline with successive validator gates and fail branches at each stage

The idea sounds obvious: run FHIR Bundle validation in continuous integration, and stop bad payloads from ever landing in a downstream environment. In practice, most teams still validate manually, or only run the check inside the app at runtime. That gap is where regressions slip through, and closing it is one of the higher-return moves an integration team can make.

For the wider argument on why validation matters at all, what really breaks when you skip Bundle validation is the primer, and FHIR background reading collects the rest of the series on the home page. This piece is about how to wire the check into a pipeline that runs on every commit.

Start with a Fixture Set That Actually Represents Traffic

The first mistake is running CI validation against Bundles that no real system produces. A synthetic Patient with one Observation is not a realistic fixture. Grab five or ten real Bundles from an integration test environment, scrub any PHI, and check them into a fixtures directory in the repo.

That set becomes the CI baseline. When a new field is added to the generator, the fixture regenerates; when the generator regresses, the fixture no longer validates and the build breaks. The alternative is discovering the regression when a partner reports a broken feed.

Wire the Validator Into the Test Command

The simplest wiring is a shell step that walks the fixtures directory and pipes each Bundle through a validator command. If the exit code is non-zero, the CI step fails. Most FHIR validators support this mode; some emit an OperationOutcome on failure that can also be captured as a build artifact.

The site's Bundle validator is the same shape of check but interactive. In CI you want the non-interactive equivalent, which most validator CLIs provide as a --strict or --fail-on-error flag.

CI pipeline gates: commit triggers build, build feeds validator gate, validator gate feeds deploy, with fail branches labelled at each gate

Decide the Failure Model Up Front

Not every validator warning should break the build. Structural errors, yes. Missing required elements on a profile, yes. Deprecated terminology bindings that will emit warnings for months while the value set is updated, no; those you want as informational output, not build breakers.

Pick the severity level that turns into a red build. Errors and fatals are usually the right bar for CI. Warnings can be logged and reviewed, but if every warning breaks the build, the team learns to skip validation instead of fixing it.

Add a Report That Somebody Reads

A CI check that passes silently is fine. A CI check that fails silently is worse than no check at all. Emit a short report on every run: how many Bundles validated, how many failed, what severities were seen. Pipe it to the build log or attach it as an artifact.

The report is what makes the check credible over the long run. When a partner asks "how do you know your outbound Bundles are valid" the answer is a report link, not a promise. It also makes validation output easier to read because the report can group errors the way a human would.

Handle the Receiver-Side Case Separately

CI catches producer-side bugs. It cannot catch receiver-side profile mismatches, because the receiver's profile package is not always available in the build environment. That is why a Bundle that passes locally but the receiver rejects is a distinct failure mode with a distinct remedy.

The right calibration is to run producer-profile validation in CI, and to add a separate integration test that submits sample Bundles against a mocked or staged receiver. The two checks catch different classes of bug and are worth having in parallel.

The Payoff

A working CI validation setup turns Bundle bugs into build failures instead of on-call pages. The extra ten seconds per commit is trivial next to the hours saved on the other end. Once the fixtures are realistic and the report is readable, the rest becomes routine, which is the goal.

Sources