Structured Error Handling
Design structured API error responses with AI — machine-readable error codes, actionable messages, validation details, and consistent error patterns that help consumers debug instantly.
Premium Course Content
This lesson is part of a premium course. Upgrade to Pro to unlock all premium courses and content.
- Access all premium courses
- 1000+ AI skill templates included
- New content added weekly
🔄 Quick Recall: In the previous lesson, you built automated documentation systems. Now you’ll design the error handling that determines whether API consumers spend 5 minutes or 5 hours debugging integration issues.
Error responses are the most underdesigned part of most APIs. When everything works, any API feels decent. When something fails — and it will fail — the quality of your error response determines whether the consumer can fix it in minutes or has to open a support ticket. AI helps design structured, consistent error patterns that make every failure a learning experience, not a mystery.
Error Response Schema
AI prompt for error schema design:
Design a standard error response schema for my REST API. Create: (1) a base error structure that every error response follows — with code (machine-readable string), message (human-readable), details (array for field-level errors), request_id (for tracking), and documentation_url (link to the specific error in docs), (2) validation error format — how to represent multiple field errors in a single response with field paths, expected formats, and actual values received, (3) authentication error format — distinguish between missing credentials (401), invalid credentials (401), and insufficient permissions (403), (4) rate limit error format — including retry-after timing and limit details, (5) server error format — what to reveal (request_id for support) and what to hide (no stack traces, no internal details). Generate the OpenAPI schema component and example responses for each type.
Standard error response structure:
{
"error": {
"code": "VALIDATION_FAILED",
"message": "The request contains invalid fields.",
"details": [
{
"field": "email",
"issue": "must be a valid email address",
"value": "not-an-email"
}
],
"request_id": "req_abc123",
"documentation_url": "https://api.example.com/docs/errors#VALIDATION_FAILED"
}
}
Error Code Taxonomy
AI prompt for error code catalog:
Create a comprehensive error code catalog for my API. Domain: [DESCRIBE YOUR API]. Organize error codes by category: (1) VALIDATION_* — input validation failures (VALIDATION_FAILED, VALIDATION_MISSING_FIELD, VALIDATION_INVALID_FORMAT, VALIDATION_OUT_OF_RANGE, etc.), (2) AUTH_* — authentication and authorization (AUTH_TOKEN_MISSING, AUTH_TOKEN_EXPIRED, AUTH_INSUFFICIENT_PERMISSIONS, AUTH_ACCOUNT_DISABLED, etc.), (3) RESOURCE_* — resource-related errors (RESOURCE_NOT_FOUND, RESOURCE_ALREADY_EXISTS, RESOURCE_CONFLICT, RESOURCE_GONE, etc.), (4) RATE_* — rate limiting (RATE_LIMIT_EXCEEDED, RATE_LIMIT_BURST, etc.), (5) PAYMENT_* — payment-related if applicable, (6) INTERNAL_* — server errors (INTERNAL_SERVER_ERROR, INTERNAL_SERVICE_UNAVAILABLE, INTERNAL_TIMEOUT). For each code: HTTP status, human-readable message, suggested consumer action, and a documentation section.
Error code mapping:
| Error Code | HTTP Status | When It Occurs | Consumer Action |
|---|---|---|---|
| VALIDATION_FAILED | 400 | Request body fails validation | Check details for specific fields |
| VALIDATION_MISSING_FIELD | 400 | Required field not provided | Add the missing field from details |
| AUTH_TOKEN_EXPIRED | 401 | JWT/token has expired | Refresh the token and retry |
| AUTH_INSUFFICIENT_PERMISSIONS | 403 | Valid auth, wrong permissions | Request elevated permissions |
| RESOURCE_NOT_FOUND | 404 | Requested resource doesn’t exist | Verify the resource ID |
| RESOURCE_CONFLICT | 409 | Duplicate or conflicting operation | Check existing resources first |
| RATE_LIMIT_EXCEEDED | 429 | Too many requests | Wait for retry_after_seconds |
| INTERNAL_SERVER_ERROR | 500 | Unexpected server failure | Retry with exponential backoff |
✅ Quick Check: A consumer sends a POST /users request with { “email”: “test@test.com”, “name”: "" }. Your validation requires name to be 1-100 characters. Which response is more helpful? Response A:
{ "error": "Name is required" }. Response B:{ "error": { "code": "VALIDATION_FAILED", "details": [{ "field": "name", "issue": "must be between 1 and 100 characters", "value": "" }] } }. (Answer: B — it’s machine-parseable (code), identifies the exact field (name), states the rule (1-100 characters), and shows what was sent (empty string). A consumer’s code can programmatically highlight the name field and display the issue to their end user.)
Error Message Writing
AI prompt for error message improvement:
Review and improve the error messages in my API. Current messages: [LIST YOUR CURRENT ERROR MESSAGES]. For each message, rewrite it to be: (1) Specific — not ‘invalid input’ but ’email must be a valid email address’, (2) Actionable — tells the consumer what to do, not just what’s wrong, (3) Consistent in tone — professional, not blaming (‘The request is missing the required field “name”’ not ‘You forgot to include the name field’), (4) Free of internal details — no database column names, internal service names, or stack traces, (5) Properly formatted — sentence case, no trailing periods in single-line messages. Generate a before/after comparison for each message.
Error message quality levels:
| Level | Example | Problem |
|---|---|---|
| Bad | “Error” or “Bad Request” | Zero information |
| Below average | “Invalid email” | Which email? What’s invalid about it? |
| Average | “The email field must be a valid email address” | Actionable but no context |
| Good | “The email ’test@test’ is not a valid email address. Expected format: user@domain.com” | Shows what was sent, what’s expected |
| Excellent | Above + field path + error code + docs link | Machine-parseable + human-readable |
Error Handling Middleware
AI prompt for error middleware:
Generate error handling middleware for my [FRAMEWORK — Express.js/FastAPI/Go Gin] API. The middleware should: (1) catch all unhandled errors and format them as my standard error schema, (2) map common framework errors to my error codes (validation errors → VALIDATION_FAILED, auth errors → AUTH_TOKEN_INVALID, not found → RESOURCE_NOT_FOUND), (3) log the full error details internally (including stack trace) but return only the safe error response to consumers, (4) generate a unique request_id for every request (pass it through via header and include in error responses), (5) handle different error types differently: validation errors return field-level details, auth errors include the required permission, rate limit errors include retry-after headers. Include the middleware code and registration instructions.
Key Takeaways
- The quality of your error responses determines whether consumers spend 5 minutes or 5 hours debugging: a structured response with error code, field-level details, expected format, and actual value received lets them fix every issue in one pass
- String error codes in ALL_CAPS_SNAKE_CASE (VALIDATION_FAILED, RESOURCE_NOT_FOUND) are self-documenting and enable programmatic error handling — numeric codes require a lookup table and mean nothing at a glance
- Error messages should be specific, actionable, and free of internal details: “The email ’test@test’ is not valid” is actionable; “Bad Request” and “invalid input” are not; “PostgreSQL constraint violation on column user_email” leaks internal details
- Rate limit responses should include both headers (Retry-After, X-RateLimit-Limit/Remaining/Reset) for automated retry logic AND a descriptive body for debugging — consumers shouldn’t have to guess their limits
- Error handling middleware transforms error standardization from a discipline problem (each developer formats errors differently) into a systems problem (the middleware enforces the standard automatically)
Up Next
In the next lesson, you’ll build API versioning strategies — how to evolve your API without breaking existing consumers, handle deprecation gracefully, and manage the inevitable breaking changes.
Knowledge Check
Complete the quiz above first
Lesson completed!