Skip to content

Error Middleware

DodaTech 2 min read

title: "Error Middleware — Centralizing API Error Handling" description: "Error middleware centralizes API error handling by catching all exceptions and returning consistent error responses with appropriate status codes and trace information." date: 2026-06-28 lastmod: 2026-06-28 weight: 21 tags: [apis, error-handling] }

Error middleware is a centralized error handling layer that catches all exceptions from API handlers and returns consistent, structured error responses with proper status codes.

What You'll Learn

  • Building error middleware in Express and Flask
  • Mapping exceptions to status codes
  • Error logging and monitoring

Why It Matters

Centralized error handling ensures every error returns a consistent format, reducing code duplication and preventing unhandled exceptions from leaking.

Code Examples

# Flask error middleware
class AppError(Exception):
    status_code = 400
    def __init__(self, message, code=None, status_code=None, payload=None):
        super().__init__(message)
        self.message = message
        self.code = code or self.__class__.__name__
        if status_code:
            self.status_code = status_code
        self.payload = payload or {}

    def to_dict(self):
        return {
            "error": self.code,
            "message": self.message,
            **self.payload
        }

@app.errorhandler(AppError)
def handle_app_error(error):
    return jsonify(error.to_dict()), error.status_code

@app.errorhandler(404)
def handle_404(error):
    return jsonify({
        "error": "NOT_FOUND",
        "message": "Endpoint not found"
    }), 404

@app.errorhandler(500)
def handle_500(error):
    trace_id = str(uuid.uuid4())
    app.logger.error(f"Unhandled error {trace_id}: {error}")
    return jsonify({
        "error": "INTERNAL_ERROR",
        "message": "An unexpected error occurred",
        "trace_id": trace_id
    }), 500
// Express error middleware
class AppError extends Error {
  constructor(message, statusCode = 400, code = null) {
    super(message);
    this.statusCode = statusCode;
    this.code = code || this.constructor.name;
  }
}

function errorHandler(err, req, res, next) {
  if (err instanceof AppError) {
    return res.status(err.statusCode).json({
      error: err.code,
      message: err.message
    });
  }

  // Unhandled errors
  const traceId = uuidv4();
  console.error(`[${traceId}]`, err.stack);
  res.status(500).json({
    error: 'INTERNAL_ERROR',
    message: 'An unexpected error occurred',
    trace_id: traceId
  });
}

app.use(errorHandler);

Common Mistakes

1. Not Catching Async Errors

Express doesn't catch async errors by default. Wrap async handlers.

2. Different Error Formats for Different Errors

Every error type should use the same base format.

3. Not Logging Errors with Context

Log the request method, URL, user ID, and error details.

4. Swallowing Errors Without Logging

Never catch errors without logging them first.

5. No Distinction Between Expected and Unexpected Errors

Expected errors (validation) vs unexpected (database down) need different handling.

Practice Questions

  1. Why use error middleware instead of try/catch in every handler?
  2. How do you handle async errors in Express?
  3. What information should be logged for errors?
  4. How do you map custom exceptions to HTTP status codes?
  5. Why should error types extend a base error class?

Answers:

  1. Centralized handling reduces duplication and ensures consistent responses.
  2. Wrap async route handlers with a catch function or use async middleware support.
  3. Trace ID, request path, method, user, error message, stack trace (internal).
  4. Each exception class defines its own status_code.
  5. So error middleware can catch one base type and handle all specific errors.

Challenge: Build a complete error handling middleware in your preferred framework. Support custom error classes, 404 catches, 500 fallbacks, and async error handling.

FAQ

Should middleware catch all errors or let some propagate?

: Middleware should catch all errors to prevent unhandled exceptions.

How do I handle errors in background jobs?

: Log them and use a dead letter queue for retries.

What is the 404 catch-all pattern?

: After all routes, add a middleware that returns 404 for unmatched paths.

Built by the developers of DodaTech

Doda Browser, DodaZIP & Durga Antivirus Pro