OperationOutcome — The FHIR standard error format
When a FHIR server rejects a request, validates a Bundle or executes a
$operation, it answers with an OperationOutcome. This is the standard
payload that carries errors, warnings and information back to the client.
Purpose
OperationOutcome is the universal format by which a FHIR server reports the result of
an operation: HTTP 4xx/5xx error, partial Bundle transaction success, failed profile
validation, suggestion, etc. Each OperationOutcome contains one or more
issue elements, independent of one another.
Every FHIR operation — REST CRUD, search, batch/transaction, $validate,
$expand, $everything — can return an OperationOutcome in the
HTTP body or in the response.outcome field of a response Bundle.
Key fields
| Field | Type | Cardinality | Role |
|---|---|---|---|
issue | BackboneElement[] | 1..* | Mandatory. List of issues raised. |
issue.severity | code | 1..1 | fatal | error | warning | information | success. |
issue.code | code | 1..1 | Issue category. ValueSet issue-type. |
issue.details | CodeableConcept | 0..1 | Coded detail plus human text. |
issue.diagnostics | string | 0..1 | Technical diagnostic (stack trace, debug only). |
issue.location | string[] | 0..* | XPath/FHIRPath to the offending node. Deprecated in R5 in favour of expression. |
issue.expression | string[] | 0..* | FHIRPath expression identifying the faulty element. |
Severity and issue.code
The five severity levels:
fatal— the operation could not be carried out, indeterminate state.error— the operation failed, stable state.warning— the operation succeeded but with a warning (e.g. deprecated field).information— non-blocking message (e.g. suggestion).success— unusual, mostly for$validatesuccess returns.
The main issue.code values (ValueSet IssueType):
| Code | Meaning |
|---|---|
invalid | Invalid content (typing, structure). |
structure | JSON/XML structural error. |
required | Required element missing. |
value | Invalid value (e.g. code outside ValueSet). |
invariant | Business rule violation. |
security | Authentication or authorisation error. |
login | Login required. |
forbidden | Access denied. |
not-found | Resource not found. |
duplicate | Resource already exists. |
conflict | Version conflict (ETag). |
processing | Generic processing error. |
exception | Unexpected exception (typically 500). |
timeout | Execution timeout. |
too-costly | Request too expensive (e.g. unbounded search). |
JSON example
Example OperationOutcome returned by a server after an internal exception while reading a Patient that references an unknown Organization:
{
"resourceType": "OperationOutcome",
"id": "exception",
"text": {
"status": "additional",
"div": "<div xmlns=\"http://www.w3.org/1999/xhtml\"><p>The server encountered an unexpected condition.</p></div>"
},
"issue": [{
"severity": "error",
"code": "exception",
"details": {
"text": "Unexpected internal server error: invalid reference Patient/unknown"
},
"diagnostics": "Exception: java.lang.NullPointerException at PatientService.read:128",
"location": ["Patient.managingOrganization"],
"expression": ["Patient.managingOrganization"]
}]
} Common pitfalls
- Returning plain text instead of OperationOutcome — a conformant FHIR server ALWAYS returns an OperationOutcome on error, never a text or HTML message.
- Information leak in
diagnostics— avoid exposing a full stack trace to an external client: it can reveal version, framework, server paths. - Confusing
severity=fatalanderror— fatal means indeterminate state, partial side-effects may have occurred. - Wrong
issue.code—not-foundmust accompany HTTP 404,forbiddena 403,conflicta 409, etc. - No
location/expression— without a pointer, the client cannot know which field to fix.
Related resources
- Bundle — a transaction response includes one OperationOutcome per entry on partial failure.
- CapabilityStatement — declares supported error codes.
- OperationDefinition — describes the
$xxxoperations that may return an OperationOutcome.