The OperationOutcome a validator returns is the sender's only tool for fixing the payload. A well-designed outcome tells them what is wrong, where in the resource it is wrong, how to fix it, and how to correlate it with logs if support gets involved. A poorly-designed outcome sends the sender back to guessing. Getting this right is small work at emission time and permanent savings at support time. The site's R4 resource vetter emits FHIR-conformant OperationOutcomes for every finding. For the wider FHIR framing, more on payer-side FHIR has more.
Every Issue Has Four Fields
severity— fatal, error, warning, informationcode— categorical reason (structure, invalid, required, code-invalid, invariant)expression— FHIRPath pointer to the offending elementdiagnostics— short, actionable, stable text
Every finding your validator emits should populate all four. Skipping any of them makes the sender's job harder.
Severity Matters More Than It Looks
Fatal stops the operation. Error rejects the resource. Warning notes something worth attention but does not reject. Information is context.
A validator that treats every finding as an error is too strict. A validator that treats structural spec violations as warnings is too lax. Match severity to what the receiver actually does with the resource:
- Structural spec violation → error (the receiver cannot process this)
- Profile violation on a mustSupport element → error (the profile contract broken)
- Advisory-binding value not in the value set → warning (the code is likely fine)
- Missing optional element noted for review → information
code Categorizes The Fix
The FHIR issue-type value set gives you the vocabulary. Use it as-is. Do not invent new top-level codes.
structure— payload shape wrongrequired— required element missinginvalid— value violates a constraintcode-invalid— coded value outside a bound value setinvariant— profile invariant expression returned falsenot-supported— the operation is not implemented
Consumers already dispatch on these. For the enumeration and their intent as consumed by support, meta.profile: what it claims and what it costs to enforce touches on how they land in workflows.
expression Is The Pointer, Not location
Use issue.expression with a FHIRPath string. Patient.name[0].family beats Patient.name[0]/family and beats a legacy location array. For Bundle validators, include the Bundle path: Bundle.entry[3].resource.name[0].family.
Consumers can resolve expression against the payload. Skip location.
diagnostics Should Be Short And Actionable
Bad: "Validation failed for element."
Good: "Patient.gender must be one of male, female, other, unknown."
The difference is actionability. The good version tells the sender exactly what to send. The bad version invites a support ticket.
Stable Templates Beat Inline Interpolation
Use templates with slot placeholders. "Patient.{field} must be one of {allowed}." Fill the slots at emission time.
Consumers string-match on the template hash for triage. Drifting text breaks their tooling. Every incident where "this used to look different" happens is one where the template drifted.
Include A Correlation Id
Set Resource.id on the OperationOutcome. Include a unique per-emission identifier. Support engineers correlate outcomes with server logs using it.
Without a correlation id, "this specific incident" becomes "some incident that day."
Emit One Issue Per Distinct Problem
Do not aggregate. Two missing required elements are two issues. Two invariant failures are two issues. Consumers can render, count, and route each individually.
For the batch-pipeline case where aggregation happens downstream, resource validation in a batch pipeline covers the aggregation pattern.
Return HTTP Status That Matches
- 422 Unprocessable Entity for structural or invariant failures
- 400 Bad Request for malformed input
- 403 Forbidden for authorization failures on validation
- 200 OK for warning-only or information-only outcomes
Match the code to the reason. Do not blanket-500 on any failure.
The Short Version
Every finding gets severity, code, expression, diagnostics. Match severity to what the receiver does. Use FHIR-standard codes. Expression as FHIRPath. Diagnostics short and templated. Include correlation id. One issue per problem. Match HTTP status.

Sources
- HL7 canonical OperationOutcome specification - HL7 canonical OperationOutcome specification