Reputation: 461
I am having some issues with error handling using ExpressJS and Prisma. Whenever a Prisma Exception occurs, my entire Node application crashes, and I have to restart it. I have done some googling and have looked at the Prisma Docs for error handling, but I can't find any answers.
I know I could possibly use try
and catch
, but this feels unnecessary, as I could handle this much better with an error handler, especially when a lot of information on errors is passed through Prisma.
I have tried to implement the Express error handler like this:
// index.ts
import errorHandler from "./middleware/errorHandler";
...
server.use(errorHandler);
// errorHandler.ts
import { NextFunction, Response } from "express";
// ts-ignore because next function is required for some weird reason
// @ts-ignore
const errorHandler = (err: any, _: any, res: Response, next: NextFunction) => {
console.error(err.stack);
res.status(500).send("Internal Server Error");
};
export default errorHandler;
This works fine for normal errors, but doesn't execute for Prisma errors, but instead just crashes the Node application.
How can I implement an error handler so I can manage Prisma Expections?
Upvotes: 9
Views: 9476
Reputation: 5
your module:
@Module({
imports: [UsersModule, AuthModule, DealershipModule],
controllers: [],
providers: [
PrismaService,
{
provide: APP_FILTER,
useClass: HttpExceptionFilter,
},
],
})
export class AppModule {}
your main add this line:
app.useGlobalFilters(new HttpExceptionFilter());
try this repo: https://www.npmjs.com/package/http-exception-filter-prisma-nestjs
Upvotes: 0
Reputation: 3031
As of now (Express < 5), Express invokes the error handler automatically only when an exception is encountered when executing synchronous code. For async code, you need to manually pass the error to next()
.
As noted in the Express error handling docs:
Errors that occur in synchronous code inside route handlers and middleware require no extra work. If synchronous code throws an error, then Express will catch and process it.
For errors returned from asynchronous functions invoked by route handlers and middleware, you must pass them to the next() function, where Express will catch and process them.
You absolutely can use your Express error handler with try
and catch
like so.
try {
await prismaOperation();
} catch (e: unknown) {
next(e);
}
If you pass anything to the next() function (except the string 'route'), Express regards the current request as being an error and will skip any remaining non-error handling routing and middleware functions.
If prismaOperation
throws an error, the catch block will execute where you will have to manually pass the error to next()
. Express will then skip all remaining middlewares and execute the error handler.
Starting with Express 5, this behaviour will be automated, as noted in the docs:
Starting with Express 5, route handlers and middleware that return a Promise will call next(value) automatically when they reject or throw an error.
Upvotes: 2
Reputation: 357
I ran into this problem today and I couldn't find answers too. I believe we'll have to write our own custom error handler for Prisma exceptions and not throw the error.
try {
await prismaOperation();
} catch(e) {
throw e; // avoid this which will crash our app
/* Process Prisma error with error codes
and prepare an appropriate error message
*/
const error = prismaCustomErrorHandler(e);
res.send(error); // Sending response instead of passing it to our default handler
}
Also,
// ts-ignore because next function is required for some weird reason
In Express, error-handling functions have 4 arguments instead of 3: (err, req, res, next)
.
Express interprets a middleware function with 3 arguments as (req, res, next)
which is different from, had you ommited the 4th argument, (err, _, res)
. Hence, Express won't pass any error and your err
will be a req
object, _
(req) a res
object and res
a next
function.
Edit:
...
const error = prismaCustomErrorHandler(e);
res.send(error); // Sending response instead of passing it to our default handler
...
// Edit: Or you could process and pass the error using `next(error)` to default error handler.
The above method won't crash the app and indeed sends the response. But whether you use next
or res.send
, errors have to be processed.
Upvotes: 8