0

Writing better API error responses

Most APIs return errors like {"error": "Something went wrong"}. That's not helpful for anyone — not the frontend dev, not the user, not the on-call engineer debugging at 3 AM.

The Problem

// Bad
{"error": "Invalid request"}

// Also bad
{"message": "Error", "code": 400}

// Worst
500 Internal Server Error (empty body)

A Better Format

{
    "error": {
            "code": "VALIDATION_ERROR",
                    "message": "Email address is invalid",
                            "details": [
                                        {
                                                        "field": "email",
                                                                        "message": "Must be a valid email address",
                                                                                        "value": "not-an-email"
                                                                                                    }
                                                                                                            ],
                                                                                                                    "request_id": "req_abc123"
                                                                                                                        }
                                                                                                                        }
                                                                                                                        ```
                                                                                                                        
                                                                                                                        ### Why each field matters:
                                                                                                                        
                                                                                                                        - **`code`**: Machine-readable, stable across versions. Frontend uses this to show the right UI.
                                                                                                                        - **`message`**: Human-readable, can change. For developer debugging.
                                                                                                                        - **`details`**: Field-level errors for forms. Frontend maps these to input fields.
                                                                                                                        - **`request_id`**: Links to server logs. Makes debugging 10x faster.
                                                                                                                        
                                                                                                                        ## Implementation (Express.js)
                                                                                                                        
                                                                                                                        ```javascript
                                                                                                                        class AppError extends Error {
                                                                                                                            constructor(code, message, statusCode = 400, details = null) {
                                                                                                                                    super(message);
                                                                                                                                            this.code = code;
                                                                                                                                                    this.statusCode = statusCode;
                                                                                                                                                            this.details = details;
                                                                                                                                                                }
                                                                                                                                                                }
                                                                                                                                                                
                                                                                                                                                                // Middleware
                                                                                                                                                                app.use((err, req, res, next) => {
                                                                                                                                                                    const requestId = req.id || crypto.randomUUID();
                                                                                                                                                                    
                                                                                                                                                                        if (err instanceof AppError) {
                                                                                                                                                                                return res.status(err.statusCode).json({
                                                                                                                                                                                            error: {
                                                                                                                                                                                                            code: err.code,
                                                                                                                                                                                                                            message: err.message,
                                                                                                                                                                                                                                            details: err.details,
                                                                                                                                                                                                                                                            request_id: requestId
                                                                                                                                                                                                                                                                        }
                                                                                                                                                                                                                                                                                });
                                                                                                                                                                                                                                                                                    }
                                                                                                                                                                                                                                                                                    
                                                                                                                                                                                                                                                                                        // Unknown error — don't leak internals
                                                                                                                                                                                                                                                                                            console.error(`[${requestId}]`, err);
                                                                                                                                                                                                                                                                                                res.status(500).json({
                                                                                                                                                                                                                                                                                                        error: {
                                                                                                                                                                                                                                                                                                                    code: "INTERNAL_ERROR",
                                                                                                                                                                                                                                                                                                                                message: "An unexpected error occurred",
                                                                                                                                                                                                                                                                                                                                            request_id: requestId
                                                                                                                                                                                                                                                                                                                                                    }
                                                                                                                                                                                                                                                                                                                                                        });
                                                                                                                                                                                                                                                                                                                                                        });
                                                                                                                                                                                                                                                                                                                                                        
                                                                                                                                                                                                                                                                                                                                                        // Usage
                                                                                                                                                                                                                                                                                                                                                        app.post("/users", (req, res) => {
                                                                                                                                                                                                                                                                                                                                                            const errors = validateUser(req.body);
                                                                                                                                                                                                                                                                                                                                                                if (errors.length > 0) {
                                                                                                                                                                                                                                                                                                                                                                        throw new AppError(
                                                                                                                                                                                                                                                                                                                                                                                    "VALIDATION_ERROR",
                                                                                                                                                                                                                                                                                                                                                                                                "Invalid user data",
                                                                                                                                                                                                                                                                                                                                                                                                            400,
                                                                                                                                                                                                                                                                                                                                                                                                                        errors
                                                                                                                                                                                                                                                                                                                                                                                                                                );
                                                                                                                                                                                                                                                                                                                                                                                                                                    }
                                                                                                                                                                                                                                                                                                                                                                                                                                    });
                                                                                                                                                                                                                                                                                                                                                                                                                                    ```
                                                                                                                                                                                                                                                                                                                                                                                                                                    
                                                                                                                                                                                                                                                                                                                                                                                                                                    ## HTTP Status Codes That Matter
                                                                                                                                                                                                                                                                                                                                                                                                                                    
                                                                                                                                                                                                                                                                                                                                                                                                                                    | Code | When |
                                                                                                                                                                                                                                                                                                                                                                                                                                    |------|------|
                                                                                                                                                                                                                                                                                                                                                                                                                                    | 400 | Validation error, bad input |
                                                                                                                                                                                                                                                                                                                                                                                                                                    | 401 | Not authenticated |
                                                                                                                                                                                                                                                                                                                                                                                                                                    | 403 | Authenticated but not authorized |
                                                                                                                                                                                                                                                                                                                                                                                                                                    | 404 | Resource not found |
                                                                                                                                                                                                                                                                                                                                                                                                                                    | 409 | Conflict (duplicate email, version mismatch) |
                                                                                                                                                                                                                                                                                                                                                                                                                                    | 422 | Semantically invalid (valid JSON but wrong values) |
                                                                                                                                                                                                                                                                                                                                                                                                                                    | 429 | Rate limited |
                                                                                                                                                                                                                                                                                                                                                                                                                                    | 500 | Server bug |
                                                                                                                                                                                                                                                                                                                                                                                                                                    
                                                                                                                                                                                                                                                                                                                                                                                                                                    ## Rules
                                                                                                                                                                                                                                                                                                                                                                                                                                    
                                                                                                                                                                                                                                                                                                                                                                                                                                    1. **Never return 200 for errors**. Some APIs do `200 {"success": false}` — this breaks HTTP tooling.
                                                                                                                                                                                                                                                                                                                                                                                                                                    2. **Never expose stack traces** in production. Log them server-side with the request_id.
                                                                                                                                                                                                                                                                                                                                                                                                                                    3. **Use consistent error codes** across your API. Document them.
                                                                                                                                                                                                                                                                                                                                                                                                                                    4. **Include the request_id** in every response (success too). It's the fastest path from "it's broken" to "here's why".
                                                                                                                                                                                                                                                                                                                                                                                                                                    5. **Validate early, fail fast**. Don't process half the request then error on field 7.
                                                                                                                                                                                                                                                                                                                                                                                                                                    
                                                                                                                                                                                                                                                                                                                                                                                                                                    ---
                                                                                                                                                                                                                                                                                                                                                                                                                                    
                                                                                                                                                                                                                                                                                                                                                                                                                                    How does your API handle errors? I'd love to see other patterns.

All Rights Reserved

Viblo
Let's register a Viblo Account to get more interesting posts.