← Back to Cloud and Distributed Systems

Web Request Error Handling

Web request error handling through status codes, retries, and failure boundaries.

Cloud and Distributed SystemsError HandlingWeb Requests

Handling web request errors well means distinguishing between failure types and responding in a way that helps both the user and the operator. A timeout, a malformed request, an expired session, and a crashed dependency are all "errors" from the caller's perspective, but they should not be treated the same way. Good error handling protects correctness first and user experience second.

Classify errors by responsibility

Client side errors usually mean the request itself should change. Examples include invalid input, missing authentication, forbidden actions, or references to resources that do not exist. Server side errors mean the request may have been valid but the system failed while trying to handle it.

This distinction maps to HTTP status codes for a reason. A 400 family response tells the client to change behaviour. A 500 family response tells the operator to inspect the service or its dependencies. Using 500 for everything hides useful information and makes retries noisy.

Make retries intentional

Some failures are transient: a network blip, a brief overload, or a dependency timeout. These may justify retry with backoff. Others are permanent: invalid credentials, unsupported input, or business rule violations. Retrying those only creates more load.

Idempotency matters here. Retrying a GET is usually safe. Retrying a POST that creates a payment or order is only safe if the server recognises duplicates by an idempotency key or other durable reference.

Return useful but safe error responses

Error payloads should be specific enough for clients to react but not so detailed that they leak internals. A validation error can name the field and rule. A generic server failure should expose a stable error code and correlation ID rather than a stack trace.

The same applies to logging. Log the rich diagnostic context on the server, but return a narrower message to the client. This keeps debugging effective without turning the API into an information disclosure channel.

Think about the full path

A request can fail before it reaches your application, inside your application, or after your code has made partial progress. Reverse proxies can reject oversized bodies. Databases can commit after the client connection is already gone. External providers can succeed but fail to return a response in time. Those cases are why side effecting endpoints need state checks and reconciliation, not just try/catch blocks.

Circuit breakers, deadlines, bulkheads, and fallback responses can reduce cascading failure, but only when the fallback is semantically safe. Returning stale catalog data may be acceptable. Returning stale account balances may not.

What good handling looks like

A well behaved web service validates early, uses precise status codes, times out downstream calls, retries only safe operations, and emits logs and metrics that let operators see which class of failure is growing. The client side complements this by showing actionable messages, preserving user input where possible, and avoiding infinite retry loops.

In short, web request error handling is not about catching exceptions after the fact. It is about modelling failure as part of the protocol. Once the system knows who should act on each failure and whether the operation may be repeated safely, the error path becomes much more reliable than a generic "something went wrong" screen.