API Errors and Problem Details
Create predictable, machine-readable, secure error responses.
Types of API Errors
Errors can originate from validation, authentication, authorization, resource existence, business conflicts, rate limits, dependency failures, timeouts, or unexpected server faults.
Do not expose internal stack traces, SQL statements, secrets, filesystem paths, or dependency details to clients in production.
A useful API distinguishes between errors that clients can fix and errors that require server-side intervention.
Malformed or invalid requestAuthentication failureAuthorization failureConflictSemantic validation failureUnexpected server errorMachine-Readable Error Responses
Standard Error Format
Define one predictable error structure across the API.
A useful structure can contain a machine-readable type, human-readable title, HTTP status, safe detail, and an instance identifying the request or error occurrence.
For validation failures, include structured field-level information so clients can highlight invalid inputs without parsing human-readable strings.
The error contract itself is part of your public API and should be documented.
{
"type": "https://api.example.com/problems/validation-error",
"title": "Validation failed",
"status": 422,
"detail": "One or more fields are invalid.",
"errors": [
{
"field": "email",
"code": "invalid_format",
"message": "Enter a valid email address."
}
],
"requestId": "req_01HXYZ"
}Centralized Error Handling
Business services should throw meaningful domain errors rather than constructing HTTP responses throughout the application.
The HTTP layer maps known domain errors to status codes. Unexpected errors become generic 500 responses while the complete diagnostic information is logged internally.
This separation makes services reusable outside HTTP and ensures that every endpoint follows the same error contract.
app.use((err, req, res, next) => {
req.log.error({ err }, 'Unhandled API error');
if (err.code === 'USER_NOT_FOUND') {
return res.status(404).json({
type: 'user-not-found',
title: 'User not found',
status: 404
});
}
res.status(500).json({
type: 'internal-error',
title: 'Internal Server Error',
status: 500,
requestId: req.id
});
});