ExpressExtra· 30 min read

Error Handling & Status Codes

Handle failures gracefully and return clear, correct responses to the front-end.

What you will learn

  • Use proper HTTP status codes
  • Add an error-handling middleware
  • Validate input

Why status codes matter

When something goes wrong, the front-end needs to know what went wrong — and the polite way to say so is an HTTP status code. A number in the 200s means success, 400s means "you (the caller) made a mistake", and 500s means "the server hit a problem". Sending the right code lets the front-end react correctly (show a "not found" page, a validation message, and so on).

An error-handling middleware

Two safety nets catch the common failures. Here is the order they fire in:

  1. A request comes in and Express tries to match it to one of your routes.
  2. If no route matches the URL, the catch-all 404 middleware runs and replies "Route not found".
  3. If a route runs but throws an error (or calls next(err)), Express skips to the special error handler.
  4. The central error handler logs the problem and replies with 500 so the client gets a clean message instead of a crash.

Express knows a middleware is the error handler because it has four arguments (err, req, res, next). Both of these go at the bottom, after all your routes:

Catch-all 404 + central error handler
// ... your routes ...

// 404 for unmatched routes
app.use((req, res) => {
  res.status(404).json({ error: "Route not found" });
});

// Central error handler (must have 4 args, and go last)
app.use((err, req, res, next) => {
  console.error(err);
  res.status(500).json({ error: "Something went wrong" });
});

Note: Output (requesting a URL with no matching route): {"error":"Route not found"} Output (when a route throws an error): {"error":"Something went wrong"} The first app.use has the usual two arguments, so it acts as a normal middleware — placed last, it only runs when nothing else matched, making it a perfect 404 catch-all. The second has four arguments starting with err, which is how Express recognises the error handler; console.error(err) records the real details for you, while the caller just gets a tidy 500 message (never leak raw errors to users).

Validate input

Before acting on data a client sent, check it is valid. If a required field is missing, reject the request early with status 400 (Bad Request) and a helpful message — do not let bad data into your system:

Validate before acting (400 Bad Request)
app.post("/tasks", (req, res) => {
  if (!req.body.text) {
    return res.status(400).json({ error: "text is required" });
  }
  // ... create the task ...
});

Note: Output (POST /tasks with an empty or missing text): {"error":"text is required"} if (!req.body.text) is true when text is missing or empty. In that case we return immediately with a 400 — the return is important because it stops the function before it tries to create the task. Only valid requests get past this check.

Watch out: Never trust input from the front-end. Always validate on the server — the browser’s validation can be bypassed (you learned this in the HTML forms lesson).

Q. How many arguments does an Express error-handling middleware take?

Answer: Express identifies error middleware by its four parameters: (err, req, res, next). It should be defined last.

✍️ Practice

  1. Add a catch-all 404 handler and a central error handler to an API.
  2. Validate that a required field is present and return 400 if missing.

🏠 Homework

  1. Add validation and proper status codes to your CRUD API.
Want to learn this with a mentor?

CodingClave runs guided, project-based training (28-day, 45-day & 6-month batches).

Explore Training →