Ask ten developers what "validating a FHIR Bundle" means and you will get ten reasonable answers, none of them complete. That is not a knock on the developers. The word validation is doing three or four jobs at once in the FHIR spec, and a validator only ever covers a subset of them. Knowing which subset is what separates a green build from a partner escalation.
The short answer is that a Bundle validator checks structure, cardinality, and primitive types against the base spec, and it skips almost everything about intent. If you want the broader picture of where validation sits in a US healthcare integration stack, the FHIR knowledge hub is the right entry point. This piece stays with the specific line that a Bundle validator draws.
What the Validator Reliably Catches
Structural checks are the first tier and the loudest one. The validator walks each Bundle.entry and asks whether every element exists in the base R4 schema, whether cardinality is respected, whether the type of each primitive matches the spec, and whether resourceType is set to a known resource. A missing resourceType on any entry is fatal. A Patient.gender set to "m" instead of "male" is flagged as code-invalid. A Bundle.type outside the allowed value set is a hard error.
The validator also runs FHIRPath invariants declared in the profile package it has loaded. Base R4 ships with a few, and every profile adds more. A US Core Patient without an identifier will trip the us-core-1 invariant. That is not extra effort on your side; it comes for free once you point the validator at the profile.
Primitive-type regexes are the last big win. Patient.birthDate set to "2004-01-01T00:00:00Z" when the spec expects a plain date fails structurally. A pass through the site's FHIR R4 Bundle lint catches this in milliseconds and saves you the round trip to a partner rejection.
What the Validator Deliberately Skips
Terminology is the first big gap. A structural validator does not ask a terminology server whether the LOINC code inside Observation.code actually exists in LOINC. It confirms that the Coding has a system, a code, and optionally a display. Whether the code is real, active, or in the right value set is a separate operation.
Reference resolution across the network is another skip. If Observation.subject.reference points at Patient/12345, the validator does not go and fetch that Patient. It just confirms the reference is well-formed. That gap is why you can get a fully green validation report on a Bundle that will still fail semantically when the receiver tries to store it.
Business rules that live outside the spec are the third category. A receiver may require that every Encounter has a serviceProvider, or that every claim has a specific extension. If those rules are not encoded in a profile you loaded, no validator will surface them for you.
Why the Split Matters in Practice
Once you name the split, error triage becomes routine. A structural error means the payload has a bug that will trip any receiver in the world. A terminology error means the codes are shifting under you and someone needs to update a binding. A missing business rule means the receiver has a house rule that never made it into a published IG.
The categories map to different owners too. Structural is your generator; you go fix the code that emits the Bundle. Terminology is a shared conversation with the terminology team. Business rules are a partner conversation, and the fix is either a profile update or a signed-off exception. If you want a deeper walkthrough on what the receiver enforces on top of the base spec, spec-valid vs receiver-valid FHIR Bundles is the piece that names those extra rules.
Where Profile Packages Change the Answer
The moment you load a profile package like US Core, the validator starts catching things the base spec cannot. Cardinality tightens, must-support flags appear, extensions get treated as required, terminology bindings narrow. For the exact shape of that shift, profile-aware validation when the base R4 schema falls short is where the developer-side detail lives.
The rule of thumb is simple. Base R4 is a permissive floor. Each profile you load raises the floor for a specific slice of use cases. And validator errors that always mean the same thing is the shorthand vocabulary for reading the report that comes out the other side.
Naming what a validator checks and what it skips is the difference between chasing symptoms and fixing root causes. The rest of the tooling gets easier once the split is in your head.

Sources
- HL7 FHIR core specification - HL7 FHIR core specification, Validation section: canonical evergreen reference on structural, cardinality, terminology validation layers