Error Codes and Messages
About
Error codes and messages form the error-handling contract between our API and its consumers. They must be:
Predictable → Clients can programmatically respond to errors.
Descriptive → Developers can quickly debug issues.
Consistent → Same structure across all endpoints.
Poorly designed error codes make debugging painful, increase support load, and can lead to silent failures if clients can’t interpret the meaning.
Core Principles
1. Separate Machine-Readable and Human-Readable Data
Machine-readable: Error code (numeric or string key) → for programmatic handling.
Human-readable: Descriptive message → for developer/operator clarity.
Bad:
{ "error": "Something went wrong" }
Good:
{
"errorCode": "ORDER_NOT_FOUND",
"errorMessage": "Order with ID 12345 does not exist."
}
Reasoning: Codes allow clients to take specific action without parsing free text.
2. Use Consistent Code Format
String constants (e.g.,
USER_NOT_FOUND
) → easier to read and log.Or numeric ranges mapped to error domains (e.g.,
1001
for auth errors,2001
for payment errors).Avoid mixing both in an inconsistent way.
Bad:
{ "errorCode": 123 }
{ "errorCode": "InvalidOrder" }
Good:
{ "errorCode": "ORDER_INVALID" }
Reasoning: Uniform format helps in filtering and searching logs.
3. Align with HTTP Status Codes
HTTP code → high-level category of error.
Custom code → specific cause.
Example:
{
"httpStatus": 404,
"errorCode": "USER_NOT_FOUND",
"errorMessage": "User with ID 789 was not found."
}
Reasoning: HTTP status tells what class of error, custom code tells why.
4. Avoid Ambiguous Messages
Messages must clearly state the cause and, if safe, suggest resolution steps.
Bad:
{ "errorMessage": "Invalid data" }
Good:
{ "errorMessage": "Email format is invalid. Please provide a valid email address." }
Reasoning: Specificity reduces guesswork.
5. Never Leak Sensitive Data
Error messages must never expose stack traces, SQL queries, or internal file paths.
Bad:
{ "errorMessage": "java.sql.SQLException: Invalid column index at com.example.db..." }
Good:
{ "errorMessage": "Database error occurred while processing the request." }
Reasoning: Protects against information leakage attacks.
6. Include a Correlation ID
When errors occur, provide a unique identifier for tracing in logs.
Example:
{
"errorCode": "PAYMENT_DECLINED",
"errorMessage": "Payment was declined by the bank.",
"correlationId": "abc123-456xyz"
}
7. Keep Error Payload Structure Consistent
Across all endpoints, the error object should have the same fields in the same order.
Bad:
// From one API
{ "code": "USER_NOT_FOUND", "message": "User missing" }
// From another API
{ "errorCode": "AUTH_FAILED", "errorMessage": "Token expired" }
Good:
{
"errorCode": "USER_NOT_FOUND",
"errorMessage": "User missing",
"correlationId": "xyz123"
}
Reasoning: Consistency allows clients to parse errors without branching logic.
Error Code Naming Guidelines
Uppercase with underscores
"userNotFound"
"USER_NOT_FOUND"
Easy to read, standard in APIs
Domain prefix
"INVALID"
"ORDER_INVALID"
Prevents conflicts between domains
Avoid generic words
"ERROR_1"
"PRODUCT_OUT_OF_STOCK"
Specific and meaningful
Sample JSON Error Format
{
"httpStatus": 400,
"errorCode": "INVALID_INPUT",
"errorMessage": "The 'email' field must be a valid email address.",
"correlationId": "c0a80123-4567-89ab-cdef-0123456789ab",
"timestamp": "2025-08-13T10:15:30Z",
"details": [
{ "field": "email", "message": "Invalid email format" },
{ "field": "password", "message": "Password must be at least 8 characters" }
]
}
Last updated