Home > other >  How to fix issue with Express error handler not being called
How to fix issue with Express error handler not being called

Time:01-23

I know this question is being repeated again. I've already looked at other solutions and tried them already. I'd appreciate your help in debugging the issue.

I've a separate errorHandler as a middleware.

error-handler.ts:

import express, { Request, Response, NextFunction } from "express";

export const errorHandler = (
  err: Error, 
  req: express.Request, 
  res: express.Response, 
  next: express.NextFunction
) => {
  console.log('Something went wrong');
  res.status(400).send({
    message: err.message
  });
}

index.ts:

import express, { Request, Response, NextFunction } from 'express';
import { json } from 'body-parser';
import { currentUserRouter } from './routes/current-user';
import { signinRouter } from './routes/signin';
import { signoutRouter } from './routes/signout';
import { signupRouter } from './routes/singup';
import { errorHandler } from './middlewares/error-handlers';

const app = express();
app.use(json());

app.use(currentUserRouter);
app.use(signinRouter);
app.use(signoutRouter);
app.use(signupRouter);

app.use(errorHandler);

app.listen(3000, () => {
  console.log('Listening on port 3000!!!');
})

When an Error is thrown, the Express is not catching it.

signup.ts:

import express, { Request, Response } from "express";
const router = express.Router();
import { body, validationResult } from "express-validator";

const bodyValidation = [
  body('email')
    .isEmail()
    .withMessage('Email must be valid'),
  body('password')
    .trim()
    .isLength({ min: 4, max: 20})
    .withMessage('Password must be between 4 and 20 characters')
];

router.post('/api/users/signup', bodyValidation, async (req: Request, res: Response) => {
  const errors = validationResult(req);
  if(!errors.isEmpty()) {
    throw new Error('Invalid email or password');
  }
  
  console.log('Creating a user...');

  res.send({});
});

export { router as signupRouter }

I can see Error: Invalid email or password in the terminal being thrown. But Express is not catching the error being thrown.

CodePudding user response:

Express doesn't pay any attention to the return value of your route handler. You're passing an async function to router.post, which means that your function will return a promise to report its completion, rather than reporting it in the usual synchronous way. So any error thrown within the function is reported via the promise — which Express ignores.

In general, it's not a good idea to pass an async function to something as a callback if that something (Express, in this case) doesn't support handling the Promise the function returns.

In your example, you don't have any code using await, so you could just remove the async.

If you have code using await that you left out to keep the question brief (which was perfectly reasonable), you might make that an inner function you call and use the promise from:

router.post("/api/users/signup", bodyValidation, (req: Request, res: Response) => {
    const errors = validationResult(req);
    if (!errors.isEmpty()) {
        throw new Error("Invalid email or password");
    }

    console.log("Creating a user...");
    (async () => {
        // ...your code using `await` here...

        // You're all done, send the result
        res.send({});
    })().catch((error) => {
        // ...send error response...
    });
});

Note how that code catches promise rejection in order to send an error response — you wouldn't want to just leave the promise rejection unhandled.

Another way you can do that is to ensure that the entire body of that inner function is in a try/catch:

router.post("/api/users/signup", bodyValidation, (req: Request, res: Response) => {
    const errors = validationResult(req);
    if (!errors.isEmpty()) {
        throw new Error("Invalid email or password");
    }

    console.log("Creating a user...");
    (async () => {
        try {
            // ...your code using `await` here...

            // You're all done, send the result
            res.send({});
        } catch (error) {
            // ...send error response...
        }
    })();
});
  • Related