How do you pass nice error messages to clients in express?
app.use(errorHandler);
function errorHandler(err, req, res, next) {
res.send(err);
}
app.post('/login', usernameIsValid, pwdIsValid, createToken);
In usernameIsValid I create a new Error with a message and status and call next(err). Now this bypasses pwdIsValid and createToken like it should BUT the weird thing is my errorHandler logs the error without a console.log. Am I using the default error handler in express somewhere? How do I turn it off? I have tried both production and development for NODE_ENV.
On the client xhr.responseText is my error.message + what looks like a stack trace? I've even tried just to send err.message but it looks the same.
One way to handle this mess is to make each middleware (if there is an error) create an error string like req.data.err = "invalid username" and then make sure each following middleware checks req.data.err if the string is present. But this is tedious as hell >_<
I solved it. You need to apply the error handler app.use(errorHandler) dead last after all other routes. This disables the built-in error handler. Now you may pass pretty error messages to the client.
Read more here.
edit: process.env.NODE_ENV does not matter.
From the express documentation site
If you pass an error to next() and you do not handle it in an error handler, it will be handled by the built-in error handler; the error will be written to the client with the stack trace. The stack trace is not included in the production environment.
So if you want to avoid the stacktrace you only need to execute your application with the NODE_ENV set to production.
Run you application as follows:
$ NODE_ENV=production node file.js
Related
let's take this snippet for example
const express = require('express')
const bodyParser = require('body-parser')
const app = express()
app.use(bodyParser.urlencoded({ extended: false }))
app.get(...)
# all my routes #
app.use(function (err, req, res, next) {
console.error(err.stack)
res.status(500).send('Something broke!')
})
app.listen(9000)
....
if body-parser throws an error?
Maybe the client closes the connection or the request payload is too large
the client will receive an error with status code 500 from the default express error handler but it’s probably a error that should return 4xx response .
I thought of putting a middleware right after it and calling res.send with the error and status code 400.
maybe wrap all my 3rd party middle ware with try-catch handler
Or adding in my error handler middleware a huge switch case
And over time adding error thrown from middleware third party middleware and change there status code to 400
All the solutions not really bolt proof and need maintenance over time
What us the best practice any suggestions?
The body-parser module should call next(err) when it encounters an error and you can then intercept that by providing an Express error handler such as:
app.use(function(err, req, res, next) {
console.error(err.stack)
res.status(500).send('Put your content here')
});
When you define this special middleware (with four arguments), then Express will keep track of that separately as an error handler that should be called when/if some request handler calls next(err) or if a synchronous exception is caught by Express.
Express has a default error handler if you do not provide one which you can read about here. But, if you supply one, then yours will take over and you can do whatever you want from the error handler. You can even just log the error and take the user to an error page - you don't have to even send an http error status if it's a web page request. If it's an API, you should probably be using http error statuses.
what is the best practice?
Best practice is to include your own Express error handler where you will be able to intercept all errors that are sent on to next(err).
I thought of putting a middleware right after it and calling res.send with the error and status code 400 or maybe wrap all my 3rd party middle ware with try-catch handler
Your third party middleware needs to behave properly in the Express eco-system. That means that it can throw synchronously and Express will catch it automatically and send to the Express error handler. The code should not throw asynchronously (as is true for all types of code) because nobody can catch those exceptions (unless they are in promise-structured code). You shouldn't have to wrap middleware yourself.
Internal errors should generally not be 4xx errors, but rather 5xx errors. Whether or not you surface an internal error back to the end user depends entirely upon the context. Usually, the user will be shown some sort of general purpose error page. Or, if it's an API, the API will have a scheme for communicating errors and typically the API will return actual http status codes that appropriately map to the type of problem.
after further investigation, this is the best solution suited for me
simply adding another middleware after body parse
https://www.npmjs.com/package/express-body-parser-error-handler
Environment: Node.js, Express
The pattern below will forward all synchronous and asynchronous Error objects to my error handling middleware.
app.get('/', wrapAsync(async function(req, res, next) {
// synchronous error
throw new Error('oops');
// asynchronous error
//next( new Error('oops I did it again');
res.send('hello world');
}));
function wrapAsync(fn) {
return function(req, res, next) {
fn(req, res, next).catch(next);
};
}
app.use( function(error, req, res, next) {
res.send(error);
});
However what if an unexpected error occurs in part of my code where I didn't set up an Error object? Will node.js or Express detect that an error occurred in my route, create an Error object and forward it to my middleware through the wrapAsync wrapper function? This is hard for me to wrap my mind around because I'm not sure how to test for something unexpected.
Is there a pattern that ensures that all possible errors that occur in a route are forwarded to the error handling middleware without crashing the server?
However what if an unexpected error occurs in part of my code where I didn't set up an Error object?
If something throws besides your own code (a programming error or unexpected exception), than whatever threw will have created its own exception. It is convention, but not entirely required that you throw Error objects. Custom code could throw a string or its own object if it wanted to, though that is not the common convention.
An interpreter-generated exception (such as a TypeError) will always throw some type of Error object.
Will node.js or Express detect that an error occurred in my route, create an Error object and forward it to my middleware through the wrapAsync wrapper function?
That's not really the right way to think of it. It's not Express or node.js doing it. It's whatever code caused or threw the exception in the first place (either manually throwing an exception or the interpreter ran into a error that leads to an exception. That's an exception and where they come from. Because you have wrapped things in an async function, you are likely to see that exception (and it's associated Error object) in your .catch() handler.
There are however situations where you still won't see the exception. If some asynchronous code inside your wrapper uses plain callbacks (not promises) and throws an exception inside that plain asynchronous callback, then your wrapper won't catch that exception (nothing will). That's why all asynchronous code in this architecture should be using promisified asynchronous functions only because it enables the automatic error propagation that you are relying on.
Is there a pattern that ensures that all possible errors that occur in a route are forwarded to the error handling middleware without crashing the server?
No. Not if a function uses plain, non-promisified asynchronous callbacks. As described above, in that circumstance the errors will not propagate up to your wrapper.
FYI, see Express middleware cannot trap errors thrown by async/await, but why? for a scheme for building in rejected promise detection into Express. There's also the Express cousin, koa that does this more automatically as part of its architecture.
I'm running a Restful API Server based on Node.js using Express.js.
Today, I realized that someone can get information of error of my source code, including directory path of my server, when he send request using Curl like curl -X POST ~.
Error message I get:
TypeError: Cannot read property 'text' of undefined
at exports.list (/usr/local/node/XXX/routes/message.js:49:36)
at callbacks (/usr/local/node/XXX/node_modules/express/lib/router/index.js:124:37)
at param (/usr/local/node/XXX/node_modules/express/lib/router/index.js:118:11)
at param (/usr/local/node/XXXv/node_modules/express/lib/router/index.js:125:11)
How can I hide those critical information when the server displays errors?
I'd set the NODE_ENV flag to production, as the Express.JS doesn't send the stack data in this mode. I recommend you to check out the dotenv module in npm.
If you pass an error to next() and you do not handle it in a custom error handler, it will be handled by the built-in error handler; the error will be written to the client with the stack trace. The stack trace is not included in the production environment.
https://expressjs.com/en/guide/error-handling.html
Set your environment variable NODE_ENV to production when running Node.js to suppress stack traces. It’ll still be shown on the console.
You can create a middleware that deals with all unhandled errors for you.
app.use((err, req, res, next) => {
if (err) {
return res.sendStatus(500);
}
next();
});
That will return a 500 Internal Server Error status code to any user creating such an error. Remember to put this at the end of your middleware chain.
Just send them this kind of response if you don't want to send any message
res.sendStatus(500);
or you can use errorhandler in your express setting like this if you want to send stacktrace as well
var errorHandler = require('errorhandler');
.....//define app as express object
if (process.env.NODE_ENV === 'development') {
// only use in development
app.use(errorhandler())
}
I want to have a system which will either send me a text message or email based on severity of error on respective occurrence. I have done some research on the subject but I haven't been able to simplify matters.
All in all my end goal is to get notification whenever something is going wrong with my production server. In case of serious issues which are not caught at all I have used process's uncaughtException and for specific routes which are called via separate API calls I can simply use try catch blocks.
My first issue is I cannot handle errors thrown from different routes directly via my main server file.
Second is I'll have to write same kinda' code in every route for exception handling. If something could just listen to all the errors from main server file then I can do things easily.
You can use an error handling middleware in Express:
app.use(function (err, req, res, next) {
console.error(err.stack);
// do whatever you need to send a notification
res.status(500).send('Internal error');
});
See the documentation on the error handling in Express:
https://expressjs.com/en/guide/error-handling.html
Everything you ask about is explained very well there.
I'm new to Node and Sails and have been struggling with this problem for a couple of weeks now. I need to log (eventually to a file or database) all errors that occur in our Sails app. I have found a couple of answers that come close to solving this, but none seem to work 100%. I have setup things based off of the answer from this question
When using Sails v0.9.16 I setup my logging in the config/500.js file, but when using test code...
t.t;
... in my controller, Sails just prints out "ReferenceError: t is not defined". It never goes to 500.js. In Sails v0.10.0-rc5 the same test code will get to my custom 500 middleware (shown below).
Problem is in Sails v0.10.0-rc5 it appears that the middleware Router handles 400 error message before getting to my custom 400 middleware.
We have not committed to which version we are going to use, but getting this to work in one or the other would probably make up our minds.
So how do I get all errors that happen? If I am on the right track, what am I missing to get this to work?
Thanks in advance!
Not much code to show for v0.9.16...I don't think I changed anything other than adding a sails.log in the 500.js file...
Below is the custom middleware setup for v0.10.0-rc5 ...
loadMiddleware: function(app, defaultMiddleware, sails) {
// Use the middleware in the correct order
app.use(defaultMiddleware.startRequestTimer);
app.use(defaultMiddleware.cookieParser);
app.use(defaultMiddleware.session);
app.use(defaultMiddleware.bodyParser);
app.use(defaultMiddleware.handleBodyParserError);
app.use(defaultMiddleware.methodOverride);
app.use(defaultMiddleware.poweredBy);
app.use(defaultMiddleware.router); //400s do not make it past this...
app.use(defaultMiddleware.www);
app.use(defaultMiddleware.favicon);
app.use(function(req, res, next ) {
sails.log("400 error caught in middleware - " + err.stack);
next();
});
app.use(function(err, req, res, next){
sails.log("500 error caught in middleware - " + err.stack);
next(err);
});
}
In Sails v0.10, you have custom responses to handle errors, so you don't need to provide custom middleware as in your example. By default, most errors (i.e. those not specifically triggered by res.forbidden(), res.notFound() or another handler) will be served by the serverError response that lives in api/responses/serverError.js. You can customize this to do whatever you like.
If you've upgraded a v0.9 app to v0.10, you might not have the api/responses folder. No problem; just use sails new whatever in an empty directory to generate a new v0.10 project and copy the api/responses folder from the new project to your old one!