issue.code Vocabulary and What It Actually Means

The issue.code field on OperationOutcome carries a small vocabulary of categorical reasons. Each code implies a different fix, and knowing the top ten by heart saves the trip to the spec on every incident. The site's OperationOutcome reader surfaces each code with a plain-English hint. For the wider FHIR framing, more FHIR implementation patterns has more.

The Codes You Meet Most Often

  • structure — the payload does not match the base spec's structure. Fix: reshape the payload.
  • required — a required element is missing. Fix: populate the element.
  • invalid — a value violates a general constraint. Fix: read the diagnostics and correct the value.
  • value — a value is not one of the allowed literals. Fix: pick a valid value.
  • invariant — a profile invariant expression returned false. Fix: read the invariant, adjust the payload.
  • security — the operation was rejected on authorization grounds. Fix: check scopes and permissions.
  • login — authentication failed. Fix: refresh the token.
  • forbidden — the caller is authenticated but not permitted. Fix: escalate access, not retry.
  • duplicate — a uniqueness constraint fired. Fix: send an update instead of a create, or resolve the conflict.
  • not-supported — the server does not implement this operation. Fix: use a supported alternative.

Ten codes covers most incidents. For the ones outside the list, the spec's OperationOutcome page enumerates the rest.

`code-invalid` And Terminology

code-invalid is a specific issue: a coded value is not in the value set bound to the element. It surfaces when a terminology binding is required and the payload uses a code outside the binding.

Fix depends on the binding strength. If required, pick a code from the value set. If extensible, either pick a code or add one via the extension mechanism. If preferred or example, the binding is advisory and the code should still be accepted — the server may be applying the check more strictly than the spec demands.

`structure` vs `invalid`: The Subtle Split

structure fires when the payload's shape is wrong — required cardinality violated, unknown element present, malformed JSON. invalid fires when the shape is fine but a value inside it is wrong. Sometimes servers use them interchangeably. Read the diagnostics to distinguish.

For the routing pattern, severity vs diagnostic details: which one drives your next step covers the mechanic.

`not-supported` Deserves a Separate Path

Retrying a not-supported response is a mistake. It will fail the same way every time. The right response is to fall back to a supported operation — either a different endpoint, a different verb, or a different shape of request.

For clients that dispatch on server capability, the CapabilityStatement is the map. Reading it once at startup and caching the answer avoids most not-supported responses altogether.

`duplicate` Is Often A Race, Not A Bug

Two concurrent creates for the same conditional-create query, or two clients issuing the same POST inside a small window, produce duplicate. The right response is usually to fetch the existing resource and use it, not to fail the whole workflow.

`security` vs `forbidden` vs `login`

  • login — no valid authentication
  • security — general security-related rejection
  • forbidden — authenticated, but not permitted for this operation

Different fixes. login retries after re-authenticating. forbidden does not retry — the caller needs different permissions. security needs the server's diagnostics to tell the two apart.

Building A Dispatch Table

The right shape is a small table keyed by (severity, code) mapping to a handler. Fatal-anything → alert. Error-structure → surface to developer. Error-duplicate → fetch existing. Error-login → refresh token and retry. And so on.

That table lives in one file and is where every incident-response fix accumulates. For the design side of writing your own codes, designing your own OperationOutcome for a custom validator covers the pattern.

The Short Version

Ten codes cover most incidents. Structure vs invalid is a subtle split. not-supported does not retry. duplicate is often a race. Every dispatch table indexes on (severity, code). For the base pattern, reading an OperationOutcome for the first time is the entry.

Dataviz-particles diagram of a code-and-severity dispatch matrix with ten most-common issue codes and their handlers as particle-cluster cells on a light navy field with dataviz-blue accents

Sources