🚨 C5 · Error Handling Middleware: (err, req, res, next)
C5 · Error Handling Middleware: (err: Express's error-catching middleware is like the **single fire exit in a building**: normal middlewares take 3 parameters (`req, res, next`),
Express's error-catching middleware is like the **single fire exit in a building**: normal middlewares take 3 parameters (`req, res, next`), but the ONLY way to tell Express "I am an error handler" is by taking exactly **4 parameters** (`err, req, res, next`) — this is not a keyword, Express distinguishes it purely by reading the parameter COUNT of your function (`fn.length === 4`). When you call `next(err)` inside a route, Express abandons the normal chain and looks for the next 4-parameter middleware. In Spring the equivalent is `@RestControllerAdvice` + `@ExceptionHandler` — there, matching is done by exception TYPE via annotation; in Express, every error is manually routed to ONE catch-all middleware via `next(err)`. So why does Express hide this behind such a "quiet" rule (parameter count)? Because the framework itself is minimal — it does not impose a separate "error class" concept, it expects you to use JavaScript's own mechanisms (function signature). The critical point for a tester: this middleware's REGISTRATION ORDER is just as critical as in C3 — if it is defined BEFORE the routes, Express can never reach it, because at that point in the chain no error has been thrown with `next(err)` yet.
The 4-Parameter "Secret" Signature
**🐞 Defect Birth — if the error-catching middleware is defined BEFORE the routes** **Code:** the 4-parameter `(err, req, res, next)` middleware was placed at the VERY TOP of the file, before the route definitions. **What happens:** a `GET /api/v1/bugs/999` request (a non-existent id) is sent; the route calls `next({status:404, ...})`, but Express looks for an error middleware that comes AFTER this point in registration order — it never looks backward. Since none is found, Express returns its own DEFAULT error page (HTML, containing a stack trace). **Why sneaky:** the developer says "I wrote my error handler" and it passes code review — the code IS genuinely correct, only its POSITION in the file is wrong. The result is an HTML error page instead of the expected `{"error": "Bug not found"}` JSON. **Where the tester catches it:** when automation tries to parse the body with `response.json()` and gets `SyntaxError: Unexpected token '<'` — mistaking HTML for JSON and trying to parse it is the signature of this error class (see GROUP J).
🎬 The Magic of 4 Parameters: How Express Recognizes an Error Handler
Express: searching for 4-param
Not found: HTML page
The route handler calls `next({status:404, ...})` for a non-existent bug — handing the error into the chain.
Express looks for a middleware that comes AFTER THIS POINT in registration order, taking exactly 4 parameters.
IN THE CORRECT ORDER: if the error handler is defined AFTER the routes, it is found — a proper JSON error body is returned.
IN THE WRONG ORDER: if the error handler is defined BEFORE the routes, Express never SEARCHES it — it falls back to its own default HTML page.
The lesson — when automation calls `response.json()` it tries to parse HTML and crashes. For a tester this is the most concrete evidence of a "registration order" bug.
From next(err) to a JSON Error Body
Route hands off the error…
On a not-found/unauthorized case, next(err) exits the normal chain.