How do you handle errors and return meaningful error responses in a REST API?
Learn how to handle errors in a REST API: correct HTTP status codes, RFC 7807 problem details, consistent bodies, logging, and safe production responses.
Expected Interview Answer
You handle errors by returning the correct HTTP status code together with a consistent, machine-readable error body that explains what went wrong, why, and ideally how to fix it.
Use status codes accurately: 4xx for client errors (400, 401, 403, 404, 409, 422, 429) and 5xx for server errors (500, 502, 503). Return a structured payload — often the RFC 7807 Problem Details format with type, title, status, detail, and instance — plus a stable error code and any field-level validation errors. Handle errors centrally through middleware, never leak stack traces or internal details in production, log the failure with a correlation ID, and keep the shape consistent so clients can parse it reliably.
- Clients can react programmatically to failures
- Consistent shape simplifies client code
- Correct status codes aid caching and tooling
- Correlation IDs speed up debugging
- No leaked internals improves security
AI Mentor Explanation
When a batter is given out, the umpire doesn't just walk away silently — they raise a clear signal that says exactly why: LBW, caught, or run out. A meaningful API error is that unambiguous signal: the status code is the raised finger, and the error body is the specific dismissal type so everyone knows what happened. A vague reaction would leave players and scorers guessing, just as a bare 500 with no detail leaves clients stuck.
Step-by-Step Explanation
Step 1
Choose the right status code
Map failures accurately: 400/422 for bad input, 401/403 for auth, 404 for missing, 409 for conflict, 5xx for server faults.
Step 2
Define a consistent error shape
Adopt a standard body such as RFC 7807 Problem Details with type, title, status, detail, and a stable error code.
Step 3
Centralise handling
Catch errors in one middleware or handler so every response has the same format and codes.
Step 4
Log with correlation IDs
Record the full error server-side with a request/trace ID that also appears in the client response for support.
Step 5
Sanitise for production
Never expose stack traces or internal messages; return safe, generic detail for unexpected 5xx errors.
What Interviewer Expects
- Accurate use of 4xx vs 5xx status codes
- A consistent, structured error body (e.g. RFC 7807)
- Centralised error-handling middleware
- Not leaking stack traces or internals in production
- Logging with correlation IDs and stable error codes
Common Mistakes
- Returning 200 OK with an error message in the body
- Using 500 for everything, including client input mistakes
- Inconsistent error shapes across endpoints
- Leaking stack traces or database errors to clients
- No stable error code, forcing clients to parse human messages
Best Answer (HR Friendly)
“When something goes wrong, the API should clearly say what happened and why, using a standard code and a helpful message instead of a vague failure. This lets the app respond correctly and helps developers fix problems quickly, while keeping sensitive internal details hidden.”
Code Example
class ApiError extends Error {
constructor(status, code, detail, errors) {
super(detail)
this.status = status
this.code = code
this.errors = errors
}
}
// Route throws a typed error
app.post('/api/users', (req, res, next) => {
if (!req.body.email) {
return next(new ApiError(422, 'VALIDATION_ERROR', 'Request validation failed', [
{ field: 'email', message: 'email is required' },
]))
}
// ...
})
// Central handler (registered last)
app.use((err, req, res, next) => {
const status = err.status || 500
const traceId = req.id
if (status >= 500) logger.error({ err, traceId })
res.status(status).json({
type: `https://api.example.com/errors/${err.code || 'INTERNAL'}`,
title: status >= 500 ? 'Internal Server Error' : err.message,
status,
code: err.code || 'INTERNAL',
detail: status >= 500 ? 'An unexpected error occurred' : err.message,
errors: err.errors,
traceId,
})
})Follow-up Questions
- What is the RFC 7807 Problem Details format?
- When would you use 422 instead of 400?
- How do you avoid leaking sensitive information in error responses?
- Why include a correlation or trace ID in errors?
- How do you handle validation errors with multiple fields?
MCQ Practice
1. Which status code best fits a request that is well-formed but fails business validation?
422 (or 400) signals the request was understood but semantically invalid; 500 wrongly blames the server for client input errors.
2. What is a key risk of returning raw stack traces to clients?
Stack traces can reveal file paths, libraries, and logic that help attackers, so production errors should be sanitised.
3. Why include a stable error code in responses?
A stable machine-readable code lets clients branch on error type reliably, even if the human message text changes.
Flash Cards
4xx vs 5xx? — 4xx means the client made a mistake (bad input, auth, not found); 5xx means the server failed to fulfil a valid request.
What is RFC 7807? — A standard Problem Details JSON format with type, title, status, detail, and instance fields for consistent API errors.
Why a correlation/trace ID? — It ties a client-visible error to server logs, making support and debugging fast without exposing internals.
Why not return 200 for errors? — Returning 200 with an error body breaks HTTP semantics and tooling; the status code should reflect the actual outcome.