A 401, 403 or 429 from a model provider looks like an availability problem, but each one is also a statement about the API key behind the call: whether it is valid, what it is allowed to do, and how much it has already spent. Teams that treat these responses only as outages retry them, rotate keys at random, or raise limits, and in doing so can miss a leaked key being abused. This guide covers the documented error responses of the OpenAI, Anthropic, Azure OpenAI and Google Gemini APIs, ranks the likely causes of each, shows where to look, and separates the fixes from the signals that a key has been stolen. It is for platform engineers, AI application developers and security teams who own model provider credentials. Key protection itself is covered in the LLMjacking Guide. Error strings and headers were checked against provider documentation on 11 November 2026; providers change them, so re-check before relying on an exact string.
Key takeaways
- Read the body, not just the status. One 429 can mean "slow down" or "out of money", and only the error type, code and headers tell you which. Retrying a spend or quota 429 never succeeds.
- 401 is about the credential, 403 about the context. 401 means the key, organisation or source IP is not accepted; 403 means the key is recognised but the project, region, model or permission is not allowed.
- Retries can make it worse. OpenAI and Azure both state that failed requests still count toward per-minute limits; stacked SDK and application retries multiply load.
- Unexpected 429s are a security signal. A key that hits its limit or spend cap without a matching change in your own traffic may be in someone else's hands. Check usage by key before raising limits.
- Leaked keys are blocked. Google documents a specific message for keys reported as leaked. The fix is a new key and removing the old one from wherever it was exposed, not a support ticket.
How the three codes differ
| Status | Question it answers | Retry? | Security reading |
|---|---|---|---|
| 401 Unauthorized | Is this credential valid here at all? | No: fix the key, header or IP allowlist | Revoked or rotated key still deployed; or an attacker testing stolen keys |
| 403 Forbidden | Is this valid credential allowed to do this, from here? | No | Project, region or model restrictions working as intended; probing for models a key cannot reach |
| 429 Too Many Requests | Has the caller exceeded a rate, quota or spend limit? | Only rate limits, with backoff; never spend or credit limits | Runaway agent loop, or consumption by an unauthorised user of the key |
Provider error reference
Strings are quoted from each provider's documentation as checked on 11 November 2026.
| Provider | Status and identifier | Documented meaning | First action |
|---|---|---|---|
| OpenAI | 401 "Invalid Authentication" | Wrong key or requesting organisation | Confirm key and organisation/project headers |
| OpenAI | 401 "Incorrect API key provided" | The requesting API key is not correct | Check which secret the process actually loaded; regenerate if needed |
| OpenAI | 401 "You must be a member of an organization to use the API" | Account is not part of an organisation | Have an organisation owner invite the account |
| OpenAI | 401 "IP not authorized" | Request IP does not match the project or organisation IP allowlist | Check egress IP (NAT, proxy, new region) against the allowlist |
| OpenAI | 403 "Country, region, or territory not supported" | Request from an unsupported location | Check egress location of the workload |
| OpenAI | 429 "Rate limit reached for requests" | Sending requests too quickly | Back off, honour Retry-After |
| OpenAI | 429 "Credit balance exhausted" (credit_balance_exhausted) | No prepaid credits remain | Do not retry; investigate usage, then add credit |
| Anthropic | 401 authentication_error | Problem with the API key | Verify the x-api-key value and workspace |
| Anthropic | 403 permission_error | Key lacks permission for the resource | Check workspace and model access |
| Anthropic | 429 rate_limit_error | RPM, input or output token rate exceeded; a retry-after header may be present | Back off per retry-after |
| Anthropic | 429 rate_limit_error with enforced_spend_limit_reached | Platform spend cap reached; no retry-after | Stop retries; review spend by key |
| Anthropic | 529 overloaded_error | Service temporarily overloaded | Retry with backoff; not a key problem |
| Azure OpenAI | 429 with retry-after-ms | Deployment TPM or RPM exceeded, system capacity throttling, or a temporary limit adjustment | Compare x-ratelimit-limit-tokens with configured TPM |
| Google Gemini | 403 PERMISSION_DENIED | Can mean the project is restricted; a free-tier restriction is not fixed by a new key in the same project | Check project tier and billing link |
| Google Gemini | "Your API key was reported as leaked. Please use another API key." | Google has blocked a publicly exposed key | Treat as an incident: rotate and find the exposure |
| Google Gemini | 429 RESOURCE_EXHAUSTED | Rate or quota exceeded | Exponential backoff; check quota |
Anthropic's documentation also lists a user-set spend limit returned as 400 invalid_request_error with a message beginning "You have reached your specified API usage limits", so a spend problem does not always arrive as a 429. Every Anthropic error body includes a request_id, also returned in the request-id header; record it for support and for correlation.
Diagnosing 401: the credential is not accepted
Likely causes, most to least common:
- The process loaded a different secret: an old value cached in a container image, a
.envfile overriding the secret manager, or the wrong environment's secret mounted. Log a short fingerprint (for example the last four characters or a hash) of the key at startup, never the key. - The key was rotated or revoked: by a teammate, by an automated rotation, or by the provider after a leak report. Check the provider console's key list and audit log for the key's status and last change.
- Header or endpoint mismatch: OpenAI uses
Authorization: Bearer; Anthropic usesx-api-key; Azure OpenAI uses anapi-keyheader or Entra ID tokens against a resource-specific endpoint. A key sent to the wrong provider, region or resource endpoint returns 401. - Organisation or project scope: an OpenAI key used with an organisation header it does not belong to, or an account outside any organisation.
- IP allowlist: new NAT gateway, a CI runner pool or a move to another region changed the source address.
Where to look: application startup logs (key fingerprint, endpoint, organisation header), the provider console's key list and last-used time, and egress IP from the workload. Fix: correct the secret reference in the secret manager and redeploy; do not paste a working key into code or CI variables as a stopgap. See the API Key Management Guide.
Diagnosing 403: valid key, wrong context
- Model or feature access: the project or workspace has not been granted the model, or the model was retired. Confirm the model identifier against the provider's current model list.
- Project restrictions: per-key permission settings (for example read-only or endpoint-restricted keys) block the call. Prefer narrowing a key to widening it: create a correctly scoped key for this workload.
- Location: OpenAI documents a 403 for unsupported countries, regions or territories, which can appear when a workload's egress moves.
- Billing tier: Google documents that a free-tier restriction returns 403
PERMISSION_DENIEDand that the project must be linked to a Cloud Billing account; a new key in the same project does not help. - Cloud IAM in front of the model: on Azure OpenAI and Vertex AI the caller may authenticate with a cloud identity instead of a key, and 403s then come from role assignments. Use the Azure AuthorizationFailed Troubleshooting Guide or the Google Cloud PERMISSION_DENIED Troubleshooting Guide.
Diagnosing 429: rate, quota or spend
Which limit was hit
| Provider | Limit dimensions | Headers to read |
|---|---|---|
| OpenAI | RPM, RPD, TPM, TPD, IPM; set at organisation and project level, not per user; vary by model | x-ratelimit-limit-requests, x-ratelimit-remaining-tokens, x-ratelimit-reset-requests and related; Retry-After |
| Anthropic | RPM, input tokens per minute (ITPM), output tokens per minute (OTPM) per model class; token bucket replenished continuously; cached reads do not count toward ITPM | anthropic-ratelimit-requests-remaining, anthropic-ratelimit-input-tokens-remaining, anthropic-ratelimit-output-tokens-reset and related; retry-after |
| Azure OpenAI | TPM quota per subscription, region, model and deployment type, assigned to deployments in 1,000 TPM increments; RPM derived from TPM by a model-specific ratio and evaluated over short windows of about 1 or 10 seconds | x-ratelimit-remaining-tokens, x-ratelimit-remaining-requests; retry-after-ms |
| Google Gemini | Project rate limits and quota | Status RESOURCE_EXHAUSTED; backoff |
Rate limit versus money limit
- Rate limit: transient. OpenAI's guidance is to retry 429 and 503 with exponential backoff and jitter, treat
Retry-Afteras a minimum wait, cap attempts and total retry time, and not retry quota or billing errors. - Spend or credit limit: persistent until a person acts. Anthropic documents that a platform spend cap 429 carries no
retry-afterand fails until access resumes at the start of the next month or the tier is raised; OpenAI returnscredit_balance_exhausted. - Burst shape: Azure evaluates RPM over 1 or 10 second windows, and Anthropic notes a 60 RPM limit may be enforced as 1 request per second, so a burst of parallel agent calls can be throttled even when the per-minute total is low.
- Tokens, not requests: large prompts exhaust TPM or ITPM with few requests. Prompt caching (where supported) and smaller contexts reduce token pressure more than request pacing does.
Retry hygiene
Choose one retry layer. Azure's documentation advises setting the SDK's max_retries to zero when you add your own retry library, and OpenAI warns that SDK retries plus application retries multiply requests. Agents add a third layer: a tool loop that re-plans after an error. Give each agent run a token and request budget and stop the run when it is exhausted.
When the error is a security signal
Stolen model provider keys are resold and used for high-volume inference, which surfaces to the owner as unexplained 429s, spend caps reached early, or a provider leak block. MITRE ATT&CK classifies this as T1496.004 Cloud Service Hijacking, and the theft itself as T1552.001 Credentials In Files when keys are taken from code or configuration. The OpenCode console breach is a recent case of stored OpenAI, Anthropic and Google keys being stolen and abused.
| Observation | Benign explanation to rule out | Escalate when |
|---|---|---|
| 429 or spend cap with no traffic change in your own logs | Provider-side temporary limit adjustment (Azure documents these) | Provider usage by key exceeds your application's own request count |
| Usage on models or regions you do not use | A new feature shipped by another team on the same key | No owner claims it |
| 401 bursts from unknown sources against your gateway | Misconfigured client after rotation | Many distinct keys tried from few addresses |
| Gemini leaked-key message | None | Always: rotate and trace the exposure |
Response steps are in the LLMjacking Response Playbook and the AI model provider API keys leak response guide.
Fixing without creating new risk
- Classify first: record status, error type or code, request ID and rate limit headers for the failing call.
- For 401 and 403: fix the secret reference, endpoint or scope; if a key must be replaced, create the new key, deploy it, confirm traffic on it, then revoke the old one.
- For rate 429: add jittered backoff in one layer, reduce concurrency, cache prompts, then request a higher tier if demand is genuine.
- For spend 429: compare provider usage by key with your own logs before adding credit or raising a cap. If they disagree, treat it as a suspected compromise.
- Test in a staging project: with its own key and low limits, so throttling behaviour can be exercised safely.
- Roll back: keep the previous key valid only for the short overlap window and the previous limit configuration recorded, so a bad deployment can be reverted without re-issuing secrets.
Routing all calls through an AI gateway gives one place to enforce per-application budgets, map provider errors to consistent internal codes and hold provider keys away from application code. See the AI Gateway and LLM Gateway Guide and How to Set spend limits on llm api keys.
Detection and measurement
- Log per call: application, key fingerprint, model, status, provider error type or code, request ID, tokens in and out, and the remaining-limit headers.
- Reconcile daily: provider console usage by key against your own logged tokens; a gap is the strongest early indicator of key misuse.
- Alert: on spend cap or credit exhaustion events, on any leaked-key response, and on 401 rates above baseline after a rotation window closes.
| Metric | Target |
|---|---|
| Share of 429s that are spend or credit limits | Near zero; each one reviewed |
| Gap between provider-reported and internally logged tokens per key | Within a few per cent |
| Retries per successful call | Low and stable; spikes show retry storms |
| Keys without a named owner and spend limit | Zero |
| Time from leak signal to old key revoked | Hours, not days |
Common failure patterns
- Retrying a spend limit: SDK retries hammer an endpoint that cannot succeed until a person acts.
- Raising limits before checking usage: a higher cap gives an attacker using a stolen key more room.
- One key for everything: every application shares a key, so one leak or one runaway loop stops all of them and usage cannot be attributed.
- Rotating by deletion: revoking the old key before the new one is deployed causes a self-inflicted 401 outage.
- Logging full keys while debugging 401s: the fix creates a new exposure in log storage.
- Ignoring 403 on retired models: agents silently fail over to more expensive models or stop working.
Framework mapping
| Framework | Reference | Relevance |
|---|---|---|
| OWASP Top 10 for LLM Applications 2025 | LLM10:2025 Unbounded Consumption | Rate, token and spend limits as a control |
| OWASP API Security Top 10 2023 | API4:2023 Unrestricted Resource Consumption | Limits on calls you expose in front of the model |
| NIST CSF 2.0 | PR.AA-01, DE.CM-09 | Managing service credentials; monitoring runtime usage |
| NIST SP 800-53 Rev. 5 | IA-5, AU-6, SC-5 | Authenticator management, log review, resource exhaustion protection |
| MITRE ATT&CK v20 | T1496.004 Cloud Service Hijacking, T1552.001 Credentials In Files | Abuse and theft of model provider keys |
Practitioner checklist
- Capture status, error type or code, request ID and rate limit headers for every failed call.
- Distinguish rate limits from spend and credit limits in code, and never retry the latter.
- Use one retry layer with jittered backoff and a cap on attempts and total time.
- Give each application its own key with a named owner, scope and spend limit.
- Rotate by overlap: deploy the new key, confirm, then revoke the old.
- Reconcile provider usage per key with internal logs daily.
- Treat leaked-key blocks and unexplained spend as incidents.
- Budget tokens and requests per agent run.
Standards and references
- OpenAI: Error codes
- OpenAI: Rate limits
- Anthropic: Errors
- Anthropic: Rate limits
- Microsoft Learn: Manage Azure OpenAI quota
- Google AI for Developers: Gemini API troubleshooting
- OWASP: LLM10:2025 Unbounded Consumption
- MITRE ATT&CK: T1496.004 Cloud Service Hijacking
Related NHI Mgmt Group resources: LLMjacking Guide, OpenAI API Keys Security Guide, Anthropic API Keys Security Guide, Rate Limiting and API Abuse Guide, AI Gateway and LLM Gateway Guide.