Designing Your Own OperationOutcome for a Custom Validator

The moment a team writes a custom FHIR validator or a domain-specific rule engine, the question comes up: how should the diagnostic output be shaped? The answer is almost always OperationOutcome — it is the spec's mechanism for reporting issues on any FHIR operation, and consuming clients already know how to read it. The site's OperationOutcome reader will accept your custom emissions the same as the canonical ones. For the wider FHIR framing, deeper FHIR walkthroughs has more.

Pick The Right Severity

  • fatal — the operation cannot proceed at all
  • error — a specific issue prevents the operation from succeeding for this entry
  • warning — the operation succeeded but here is something worth attention
  • information — the operation succeeded and here is context

Over-severity is worse than under-severity. A warning that surfaces as an error stops workloads that should have proceeded. A fatal that should have been an error creates unnecessary rollback. Match the severity to the actual behavior.

Reuse The Standard code Vocabulary

The standard vocabulary — structure, required, invalid, value, invariant, security, duplicate, not-supported, and the rest — covers the vast majority of custom cases. Reuse them. Consuming clients already dispatch on them; introducing a new code adds work everywhere.

For the enumeration and their intent, issue.code vocabulary and what it actually means is the reference.

Only Add Codes When The Standard Set Falls Short

Sometimes the domain rule does not fit any standard code. That is fine. Use business-rule as the closest match, and put the specific reason in details.coding with your own coding system. That way clients that recognise your codings can dispatch precisely, and clients that do not still fall back to the generic handling.

Do not introduce a new top-level code value. That path is closed by the spec; extending it breaks conformance.

Emit `expression` Always

Every custom outcome should carry an expression pointing at the offending element. FHIRPath is the language, dot-path form is the convention. Emit location too if you have older consumers, but do not skip expression.

For the mechanic, location vs expression: pointing at the offending element covers the split.

Diagnostics: Short, Actionable, Stable

  • Short — one or two sentences
  • Actionable — tells the reader what to do, not just what happened
  • Stable — the same issue produces the same diagnostics string across runs

Long, verbose diagnostics are worse than short, precise ones. Stability matters because support teams string-match on diagnostics for triage, and drifting text breaks their tooling.

`details.text` For The Human Summary

details.text is the shorter human summary. Some UIs display it directly instead of diagnostics. Keep it brief — a single line — and consistent with the diagnostics narrative.

details.coding is where the stable machine-readable extension goes if you have one. Consumers that recognise the coding can dispatch on it; consumers that do not fall back to the base code + severity.

One Issue Per Distinct Problem

Do not aggregate multiple issues into one issue entry. If a resource has three missing required fields, emit three issue entries with three different expressions. Consumers can render them separately, count them, and route them individually.

Aggregation into diagnostic prose is a common shortcut that loses the per-issue routing. Do not take it.

Include `id` For Correlation

Every OperationOutcome can carry a Resource.id. For custom validators, generating a unique id per outcome makes correlation across log entries much easier. Support teams appreciate it. For the pattern, OperationOutcome patterns that help your support team is the deep dive.

The Short Version

Reuse standard severity and code. Add codes only in details.coding. Emit expression. Keep diagnostics short and stable. One issue per problem. Include an id for correlation. Custom OperationOutcomes that follow those rules are drop-in for any consumer.

Dataviz-particles diagram of a custom OperationOutcome's structure with severity, code, expression, details.coding, and diagnostics annotated as designed emission fields, on a light navy field with dataviz-blue accents

Sources