Handle Cloud Errors
The Same Classes, Different Causes
Lesson 141 introduced the SDK's error classes, and they apply to every integration: a 401 is an AuthenticationError whether the request went to the direct API or to a cloud platform. What differs is the cause. On the direct API, an authentication failure usually means a wrong or revoked key. On a cloud platform, the same status can mean that the identity lacks a permission, that the model has not been enabled in the account, or that the request was sent to a region where the model is not offered.
Cloud integrations also add failures that never reach the Claude service at all. A missing credential, an unreadable identity file, or a configuration that names a project that does not exist can all stop a request before it is sent. Those errors come from the cloud's own libraries, and they may not look like API errors at all. This lesson shows how to tell the two apart, how to map each cause to the action that resolves it, and how to log the information that makes the diagnosis quick.
Two Places a Failure Can Start
Before reading an error's class, decide where the failure began. A request that never leaves the process fails in the cloud's credential or configuration layer, and a request that reaches the platform fails in the platform itself:
| Where it fails | Typical symptom | What to check |
|---|---|---|
| Before sending | An error about missing credentials, a configuration value, or an unreadable file | The credential chain, environment variables, and configuration (Lessons 164 and 167) |
| At the platform | An SDK error with a status code and a body | The platform's permissions, model access, region, and quotas |
| In the network | A connection or timeout error | The network path to the platform's endpoint (Lesson 145) |
The first row matters most for cloud deployments, because it looks different from everything else. If an application that worked yesterday now reports a credential error before any request, the cause is almost always a change in the environment, not in the API.
Mapping Status Codes to Causes
For failures that do reach the platform, the status code and the message narrow the cause. The mapping below is a working guide. The message text is the most precise evidence, and the platform's error reference is the authority for the exact wording:
| Status | Class | Common cloud cause | Action |
|---|---|---|---|
| 400 | BadRequestError | A model identifier from another platform, or a parameter the platform does not accept | Correct the identifier or the parameter for this platform |
| 401 | AuthenticationError | Missing or expired credentials | Refresh or reconfigure the credential |
| 403 | PermissionDeniedError | The identity lacks permission for the action, or the account has not enabled the model | Grant the permission, or enable the model in the account |
| 404 | NotFoundError | The model is not offered in the chosen region, or the deployment or resource name is wrong | Choose a region that offers the model, or correct the name |
| 429 | RateLimitError | Throughput or quota is exhausted for the account or the region | Back off (Lessons 142 and 146), and check the quota |
| 5xx | InternalServerError | A problem on the platform side | Retry with backoff (Lesson 143) |
Two rows are easy to confuse. A 403 says the identity may not do this, while a 404 can say the model is not there at all, and the remedy for each is different. Reading the message before acting prevents a week spent granting permissions for a model that is not offered in the region.
Classifying Cloud Failures
The diagnosis can be automated for the common cases, so the log says what to do rather than only what happened. The classifier below maps an error and its platform to a cause and an action. It uses simulated errors, so it runs offline:
"""cloud_errors.py: map an SDK error from a cloud platform to a likely cause and an action."""
from api_errors import fake_status_error
from anthropic import APIConnectionError, APIStatusError
import httpx
REQUEST = httpx.Request("POST", "https://example.invalid/v1/messages")
def diagnose(error: Exception, platform: str) -> str:
if isinstance(error, APIConnectionError):
return f"{platform}: no response; check the network path to the endpoint"
if isinstance(error, APIStatusError):
status = error.status_code
if status == 400:
return f"{platform}: bad request; check the model identifier and parameters for this platform"
if status == 401:
return f"{platform}: not authenticated; refresh or reconfigure the credential"
if status == 403:
return f"{platform}: not permitted; check the identity's permissions and the model's enablement"
if status == 404:
return f"{platform}: not found; check the region offers the model, and the name is correct"
if status == 429:
return f"{platform}: rate limited; back off and check the quota"
if status >= 500:
return f"{platform}: platform error; retry with backoff"
return f"{platform}: unrecognized failure; read the error message and the platform's error reference"
if __name__ == "__main__":
cases = [
("bedrock", fake_status_error(403, "permission_error", "not authorized", "req_1")),
("vertex", fake_status_error(404, "not_found_error", "model not found in region", "req_2")),
("foundry", fake_status_error(429, "rate_limit_error", "quota exceeded", "req_3")),
("bedrock", APIConnectionError(request=REQUEST)),
]
for platform, error in cases:
print(diagnose(error, platform))
Output:
bedrock: not permitted; check the identity's permissions and the model's enablement
vertex: not found; check the region offers the model, and the name is correct
foundry: rate limited; back off and check the quota
bedrock: no response; check the network path to the endpoint
How It Works
- Connection errors are checked first, because they carry no status and would otherwise fall through to the generic message.
- The status is mapped to a cause and an action, and each message names the thing to check. A
403points at permissions and enablement, which is where a cloud denial usually lies. - The platform name is part of every message, so a log line from a multi-platform application shows which integration failed.
- Unknown failures get a message that points to the reference, rather than a guess that could send someone in the wrong direction.
- The example errors are simulated with the helper from Lesson 141, so the classifier can be tested without access to any platform.
Before-Request Failures
Credential and configuration failures happen before a request is sent, so they will not appear in the API's request IDs, and they may come from a library other than the SDK. The application should catch them where it creates the client, at startup, and report them clearly. A failure at startup is far better than a failure on the first user request, and the factory in Lesson 167 is where such checks belong.
Logging Cloud Failures
Lesson 147's structured logs apply to cloud failures too, with two additions: the platform name, so the event is attributed correctly, and the classified cause, so an operator can act without reading the raw error. The request ID remains the key for support, when the failure reached the platform. For failures before a request, the log records the configuration step that failed, and never the credential value (Lesson 164).
Summary
Cloud integrations return the same error classes as the direct API, but the same status can have different causes on each platform. Some failures happen before any request, in the cloud's own credential and configuration layers. The status and message narrow the cause to permissions, enablement, region, identifiers, or quotas, and each cause has a different action. Classifying failures automatically, with the platform named in every log line, turns a confusing error into an instruction. The next lesson covers the extras that each cloud's SDK support adds on top of the shared client.