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 authenticationsecurity— general security-related rejectionforbidden— 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.

Sources
- HL7 canonical issue-type value set enumerating issue.code - HL7 canonical issue-type value set enumerating issue.code values