Errors & troubleshooting
Two error vocabularies apply: OAuth error codes during authorization and token exchange, and FHIR OperationOutcome resources on API calls. This page catalogs both, worst-first by how often they burn an afternoon.
Reading an OperationOutcome
Every non-2xx FHIR response is application/fhir+json with:
{
"resourceType": "OperationOutcome",
"issue": [
{
"severity": "error",
"code": "forbidden",
"diagnostics": "Scope patient/Observation.rs is not granted"
}
]
}
issue[].code is the machine-readable key; diagnostics is for humans.
Handle by code and HTTP status, and log diagnostics — don't parse it.
HTTP statuses on FHIR calls
| Status | Meaning | Usual fix |
|---|---|---|
401 |
Missing, expired, or malformed bearer token | Complete a new EHR launch; tokens are short-lived and there are no refresh tokens |
403 |
Token valid, scopes insufficient (or patient-context violation) | Check the granted scope on your token; broaden the schema and re-deploy if needed |
404 |
Unknown id, wrong partition, or a resource/route that isn't advertised | Verify the FHIR base URL and that the interaction exists in the reference |
422 |
Resource failed validation on create | Read issue[]; fix the flagged element |
429 |
Rate limited | Back off and retry with jitter |
Authorization-time failures
| Error | Likely cause | Fix |
|---|---|---|
invalid_scope |
Requested scope not in the deployed schema, or not implemented at all (patient/Observation.* doesn't exist; wildcards are rejected) |
Request a subset of your schema; consult the reference |
| redirect URI mismatch | Registered and requested redirect_uri differ — scheme, host, port, or path |
Match exactly; sandbox HTTP URIs must use 127.0.0.1, not localhost |
invalid_grant at token exchange |
Code expired, already used, or code_verifier doesn't match the challenge |
Restart the launch; verify verifier storage across the redirect |
aud rejection |
The aud parameter isn't the issuer that launched you |
Pass the iss value from the launch as aud, verbatim |
| Consent screen never appears / launch fails immediately | launch token missing, reused, or stale |
Pass launch through unchanged; launch fresh from a chart |
The classics
"My search returns nothing but the data exists in the EMR." Almost
always scope context: a patient/ scope only sees the launched patient, and
missing scopes commonly present as empty results rather than errors. Check
the token response's granted scope first.
"Works with my token from yesterday" — then 401. Access tokens are short-lived and public clients get no refresh tokens; every session starts with an EHR launch.
"Everything works in the sandbox but the portal won't let me add a scope." The selectable catalog is the sandbox EMR's advertised surface. If it's not in the reference, it isn't requestable — Observation launch scopes being the most-hit example.
"My deployed URI change isn't taking effect." Configuration changes must be re-deployed to the sandbox; the registration card shows what's actually live.
When you're stuck
The runtime contracts out-rank every doc, this one included: fetch
{fhir_base_url}/metadata and {issuer}/.well-known/smart-configuration
and trust what they advertise. If behavior contradicts them, contact the
Ava integration team through your organization's portal workspace with the
request, response, and timestamp.