I’m trying to handle errors globally in Node/Express PostgreSQL/pg with an error handler function, and when I send a Postman request to the API for creating users to try to create a user with an email that already exists in the database, it first gives a proper custom response – as the duplicateError function is called due to the error having the 23505 code – and it creates a new custom operational error and sends it as the response. But if I then try to do it again, a TypeError happens instead of the previous PG error (duplicate key value violates unique constraint) so the response sent is instead the generic response for non operational errors
TypeError: Class constructor CustomError cannot be invoked without 'new'
at C:Users\Desktopproject1backendnode_modulespg-poolindex.js:45:11
at process.processTicksAndRejections (node:internal/process/task_queues:95:5)
at async createUserService (file:///C:/Users//Desktop/project1/backend/src/models/userModel.js:15:18)
at async createUser (file:///C:/Users//Desktop/project1/backend/src/controllers/userController.js:21:19) {
status: 'fail',
statusCode: 500
}
This is the db query function:
export const createUserService = async (name, email) => {
const result = await pool.query(
'INSERT INTO users(name,email) VALUES ($1, $2) RETURNING *',
[name, email],
);
return result.rows[0];
};
This is the global error handling:
const prodErrors = (res, error) => {
if (error.isOperational) {
res.status(error.statusCode).json({
status: error.status,
message: error.message,
});
} else {
res.status(500).json({
status: 'error',
message: 'Something went wrong, try again later',
});
}
};
const duplicateError = (error) => {
const msg = 'Email must be unique';
return new CustomError(msg, 400);
};
export const errorHandler = (error, req, res, next) => {
error.status = error.status || 'fail';
error.statusCode = error.statusCode || 500;
console.log(error);
if (process.env.NODE_ENV === 'development') {
devErrors(res, error);
} else if (process.env.NODE_ENV === 'production') {
if (error.code == 23505) {
error = duplicateError(error);
}
prodErrors(res, error);
}
};
The custom error class:
class CustomError extends Error {
constructor(message, statusCode) {
super(message)
this.statusCode = statusCode;
this.status = statusCode>=400 && statusCode < 500 ? 'fail' : 'error';
this.isOperational = true;
Error.captureStackTrace = (this, this.constructor)
}
}
export default CustomError;
For other errors, for example invalid email, it works fine. But for the duplicate value error it only works on the first request, after which it gives the TypeError. I’ve been looking for an answer the whole day and have no idea why it’s not working. I’m using the latest version of Express
Also, if I try doing it directly in the db query function, the same thing happens. First error is caught and a new custom error is thrown, but the second error does not contain the code and is only a TypeError
export const createUserService = async (name, email) => {
try {
const result = await pool.query(
'INSERT INTO users(name,email) VALUES ($1, $2) RETURNING *',
[name, email],
);
return result.rows[0];
} catch (error) {
// Handle PostgreSQL unique constraint error (23505)
if (error.code === '23505') {
throw new CustomError('Email must be unique', 400); // Use 400 for a Bad Request error
}
// If it's some other error, throw it again to be handled by a global error handler
throw error;
}
};
One more thing, if I instead of sending the error to the middleware, just console.log the error in the try catch block above, it’s the same pg error on all requests. So the issue happens after the first error is sent somehow