
A failing FHIRPath expression rarely fails loud. It returns an empty collection, or a boolean that flips wrong, or a value of an unexpected type — and the calling code sees the outcome without seeing where the pipeline diverged. The debugging playbook is to walk the expression left to right and read the intermediate collections at each step. The site's FHIRPath live tryout surfaces those intermediates. For the wider FHIR framing, related FHIR walkthroughs collects supporting material.
Step One: Print the Pipeline
Split the expression at every dot and evaluate each segment separately:
PatientPatient.namePatient.name.givenPatient.name.given.first()
Each intermediate is a collection. Note the count and the type. The step where the count goes to zero, or the type diverges, is where the problem lives.
The tryout shows this stepwise. Manually splitting the expression works too — the mechanic is the same.
Step Two: Identify the Divergence Type
Failing expressions fail in a small set of ways:
- Empty collection where you expected one — the target property is absent or has a different name
- Type mismatch on a chained function —
.where()on a scalar, or.valueon a non-value type - Filter that matches zero items — the filter expression is wrong or the property is not the one being filtered on
- Empty result from a polymorphic access —
.valueon an extension whose value type differs from the expected
Each has a different fix. Naming the divergence type is the first move.
Empty at the Root
The target resource is not the shape the expression assumes. A Patient expression evaluated against an Observation returns empty. A resource whose resourceType differs is often the first thing to check.
Fix: verify the resource type. resourceType on the paste-in resource has to match the head of the expression. Or use .ofType() on a Bundle entry to narrow.
Empty at a Property Walk
The property does not exist on the resource. Common causes:
- Typo in the property name
- Nested inside a wrapper element that was skipped
- Renamed between FHIR versions (R4 → R5 drift)
- Only populated on a profile, absent on the base
Fix: read the resource JSON directly and confirm the property is there. For the collection semantics that make this common, the collection semantics that surprise you at first is the entry.
Empty at a .where()
The filter matches nothing. Common causes:
- Wrong string in the equality —
'official'vs'usual' - Filter on a property that does not exist on the item
- Case mismatch on a coded value
- Filter against a value that has a null system prefix
Fix: strip the .where() filter, print the source collection, look at the actual values, adjust the filter.
Empty at a Polymorphic Access
.value on an extension whose value is a Coding returns the Coding. .value.code returns the code. .value.system returns the system. But .valueString on the same extension returns empty — the polymorphic type is Coding, not string.
Fix: use .value.ofType() to narrow, or use the explicit polymorphic suffix once you know the type.
Type Mismatch on a Method
.first() on a boolean returns empty. .exists() on a scalar returns a boolean. Every method has a receiver-type contract, and violating it returns empty or an error.
Fix: check the type of the receiver. The tryout surfaces the intermediate types; without a tryout, refer to the spec's function table.
When It Fails on Production Only
The expression passes on the demo resource and fails on production. That means the production resource has a shape the demo does not — usually extensions, missing optional fields, or coded values from local terminologies. For the testing pattern that catches this, testing FHIRPath expressions against real production resources is the entry.
The Short Version
Walk the pipeline stepwise. Name the divergence — empty at root, empty at property, empty at filter, empty at polymorphic access, type mismatch on method. The tryout is where the intermediates become visible. For the base intuition, FHIRPath basics for someone who knows JavaScript is the entry.

Sources
- HL7 canonical FHIRPath specification defining pipeline - HL7 canonical FHIRPath specification defining pipeline semantics