Express/Node.JS middleware raising error, keeps processing - node.js

I'm beginning under NodeJS/Express and I'm facing the following problem (I probably didn't get all the tricks of async programming yet)
I've made a middleware in charge of checking if a oauth_token paramters is passed (actually implementing oAuth layer on my node server)
I'm doing this :
function myMiddle(req,res,next) {
var oAuthToken = req.query["oauth_token"];
if (oAuthToken == undefined) {
res.send(406);
res.end();
next(new Error('No token provided'));
}
/* Basically doing some DB stuff with MongoDB, connecting and using oAuthToken provided to query, etc.. */
The thing is that I expected the code to "die" when he doesn't receive the oauth_token parameters in the query string. It's actually raising me an error and returning greatly 406 error to my HTTP client, but code keeps processing behind and raises me mutable headers errors caused by my processing code after, and my script dies.
Something I'm missing? Thanks by advance.

If your oAuthToken is undefined Node.js makes a response. After that you fire next(...) which tries to make another response to the same request. This fails and you see what you see. Note that in Node.js using res.send(); and res.end(); does not stop your function. So what you need is to do the following:
function myMiddle(req,res,next) {
var oAuthToken = req.query["oauth_token"];
if (oAuthToken == undefined) {
next(new Error('No token provided')); // handle everything here
// res.send(406);
// res.end();
// unnecessary, throws errors because you try to respond twice
}
// do something if this is fine
}
or do it the other way - use res.send(406); res.end(); without next(...).

This might be late, but I just encountered this issue as well. You can actually pass the error to ErrorHandler so that the middleware would not continue to the next middleware or router while you can send the HTTP status code you want.
Your middleware
function myMiddle(req, res, next) {
// Do validate your OAuth token
// you might want to do better validation of the token here
// instead of just checking its existence
//
// var oAuthToken = req.query['oauth_token'];
//
// According to JSLint, you can just directly select the object as:
//
// req.query.oauth_token
if (req.query.oauth_token === undefined) {
// Just let the ErrorHandler does the rest
// like redirecting or just send message to client
var err = new Error('Unauthorized access.');
err.status(406); // Or 403, or any HTTP status code
// Pass it to ErrorHandler
next(err);
} else {
// Do something here, or just
next();
}
}
Your ErrorHandler
app.use(function(err, req, res, next){
if (err.status == 406) {
// You can just do res.sendStatus()
res.sendStatus(406); // Set HTTP status code as 406 and send message to client
// Or chaining res.status() with res.send()
res.status(406).res.send(); // or res.render(), or res.json()
return;
}
// Others
});
More about ErrorHandler: http://expressjs.com/ja/guide/error-handling.html

Do you have express error handling (app.use(express.errorHandler()) in your middleware stack?
Also see the Express middleware section for details on how to use next().

Related

Access request/response object outside app.use for unhandledRejection event handler

So far, I have checked that to handle error for promise in generic way, unhandledRejection event handler is the best way to do it. Just like below:
process.on('unhandledRejection', (reason,promise) => {
console.log('error: unhandledRejection');
});
Now the challenge comes when I want to access Request and Response Objects inside this event handler. So that I can generate the 500 Response in generic way and hence I wont need to add promise exception handling everywhere in the project.
I have been suggested to use:
app.use(function (req, res, next) {
process.on('unhandledRejection', function (reason,promise) {
console.error("Here I can access request objects.")
// Unregister unhandledRejection
});
});
But in above case the event listener will be registered multiple times and will only be unregistered whenever exception occurred. As the event will be registered multiple times, So the code(console.error("Here I can access request objects.")) will be triggered multiple times.
Any suggestions ? If I can access request and response objects out side the app.use?
Thanks in Advance!
By default express does handle the error. By express documentation:
Express comes with an embedded error handler that will take care of any errors that may occur in the application. This default error-handling middleware function is added at the end of the middleware function stack.
next() If you give an error to the function and do not process it in a custom error handler, this error is handled by the embedded error handler; the error is printed on the client with stack-trace. Stack-trace is not included in the production environment.
Set the NODE_ENV value of the environment variable to production to run the application in production mode .
When an error is printed, the following information is added to the response:
res.statusCodethe value of the err.statusfield comes from the field
(or err.statusCode). If this value is not in the range of 4xx or 5xx,
it will be set to 500.
res.statusMessage field is set according to
the status code.
If in production mode, the body (body) becomes the HTML of the
status code message, otherwise err.stack.
err.headers Any header specified in object.
next() If you call the function with an error after starting to write the response (for example, if you encounter an error while transmitting the response to the client) the default Express error handler will close the connection and fail the request.
When you add a custom error handler, you should authorize the default Express error handler if the headers have already been sent to the client:
function errorHandler (err, req, res, next) {
if (res.headersSent) {
return next(err)
}
res.status(500)
res.render('error', { error: err })
}
Calling the next()function multiple times with an error in your code can trigger the default error handler, even if the custom error handler middleware is in place.
This is prone to memory leak:
app.use(function (req, res, next) {
process.on('unhandledRejection',
function (reason,promise) {
console.error("Here I can access request objects.")
// Unregister unhandledRejection
});
});
Also, you can't access the response object in 'unhandledRejection', and why do you want to access that if express can handle that for you to send '500' status code to the user. It is always a good practice to catch promises whenever and wherever required. However, if some promises are still not covered there are libraries to handle it too like : express-promise-router, express-async-errors
We could emit meaningful error response with err argument in express error handler and the response will be sent to the user. for example,
app.use((err, req, res, next) => {
if (err.name === 'CustomError' && err.message === 'EmptyResponse') {
return res.status(404).send('Not Found');
}
// ... more error cases...
return res.status(500).send('Internal Server Error');
});

Response to invalid token in Socket.IO

The following code is working fine, and the client is able to connect only if there is a valid token.
But how can i handle the case of invalid token, i.e. catch error thrown by middleware through next?
Also, is there some way to respond to client?
io.use((socket, next) => {
const token = socket.handshake.headers['authorization'].split(' ');
if (token === undefined || token === null || token[0] !== 'Bearer')
return next(new Error('Invalid Token'));
jwt.verify(token[1], jwtSecretKey, (err, decoded) => {
if (err) return next(new Error('Invalid Token'));
console.log(decoded);
next();
});
});
io.use() // Handle here, if error thrown by previous middleware
io.on('connection', (socket) => {
console.log(socket.id + ' Connected');
});
From the socket.io doc, "errors passed to socket.io middleware callbacks are sent as special error packets to clients".
This means that if you call next(err), then it sends that err object to the client that looks like it will generate the error message back to the client. There does not appear to be the same type of error handler that Express has. So, if you want to handle errors in a common place, then instead of calling next(err), you can just create your own error handling function and call it instead handleErrors(socket, err). Then, you will have all the errors passed to one place and you can decide what to send back to the client.
It seems to me that socket.io messages aren't really analogous to http requests as there's no required response and no standard set of errors. In fact, most socket.io messages that generate an error would require error handling specific to that type of message, not something a generic handler can necessarily be good at. For that reason, I'd probably prefer to just handle the error in the middleware where it first occurs (which may or may not need to send something to the client) and only call some common error handling function if you want some common type of response that you can implement one place.

How to fix this "Cannot set headers after they are sent to the client" [duplicate]

I'm fairly new to Node.js and I am having some issues.
I am using Node.js 4.10 and Express 2.4.3.
When I try to access http://127.0.0.1:8888/auth/facebook, i'll be redirected to http://127.0.0.1:8888/auth/facebook_callback.
I then received the following error:
Error: Can't render headers after they are sent to the client.
at ServerResponse.<anonymous> (http.js:573:11)
at ServerResponse._renderHeaders (/home/eugene/public_html/all_things_node/projects/fb2/node_modules/connect/lib/patch.js:64:25)
at ServerResponse.writeHead (http.js:813:20)
at /home/eugene/public_html/all_things_node/projects/fb2/node_modules/connect-auth/lib/auth.strategies/facebook.js:28:15
at /home/eugene/public_html/all_things_node/projects/fb2/node_modules/connect-auth/lib/index.js:113:13
at next (/home/eugene/public_html/all_things_node/projects/fb2/node_modules/connect-auth/lib/strategyExecutor.js:45:39)
at [object Object].pass (/home/eugene/public_html/all_things_node/projects/fb2/node_modules/connect-auth/lib/authExecutionScope.js:32:3)
at [object Object].halt (/home/eugene/public_html/all_things_node/projects/fb2/node_modules/connect-auth/lib/authExecutionScope.js:29:8)
at [object Object].redirect (/home/eugene/public_html/all_things_node/projects/fb2/node_modules/connect-auth/lib/authExecutionScope.js:16:8)
at [object Object].<anonymous> (/home/eugene/public_html/all_things_node/projects/fb2/node_modules/connect-auth/lib/auth.strategies/facebook.js:77:15)
Error: Can't set headers after they are sent.
at ServerResponse.<anonymous> (http.js:527:11)
at ServerResponse.setHeader (/home/eugene/public_html/all_things_node/projects/fb2/node_modules/connect/lib/patch.js:50:20)
at next (/home/eugene/public_html/all_things_node/projects/fb2/node_modules/connect/lib/http.js:162:13)
at next (/home/eugene/public_html/all_things_node/projects/fb2/node_modules/connect/lib/http.js:195:11)
at next (/home/eugene/public_html/all_things_node/projects/fb2/node_modules/connect/lib/http.js:150:23)
at param (/home/eugene/public_html/all_things_node/projects/fb2/node_modules/connect/lib/middleware/router.js:189:13)
at pass (/home/eugene/public_html/all_things_node/projects/fb2/node_modules/connect/lib/middleware/router.js:191:10)
at Object.router [as handle] (/home/eugene/public_html/all_things_node/projects/fb2/node_modules/connect/lib/middleware/router.js:197:6)
at next (/home/eugene/public_html/all_things_node/projects/fb2/node_modules/connect/lib/http.js:198:15)
at Object.auth [as handle] (/home/eugene/public_html/all_things_node/projects/fb2/node_modules/connect-auth/lib/index.js:153:7)
Error: Can't set headers after they are sent.
at ServerResponse.<anonymous> (http.js:527:11)
at ServerResponse.setHeader (/home/eugene/public_html/all_things_node/projects/fb2/node_modules/connect/lib/patch.js:50:20)
at next (/home/eugene/public_html/all_things_node/projects/fb2/node_modules/connect/lib/http.js:162:13)
at next (/home/eugene/public_html/all_things_node/projects/fb2/node_modules/connect/lib/http.js:207:9)
at next (/home/eugene/public_html/all_things_node/projects/fb2/node_modules/connect/lib/http.js:150:23)
at param (/home/eugene/public_html/all_things_node/projects/fb2/node_modules/connect/lib/middleware/router.js:189:13)
at pass (/home/eugene/public_html/all_things_node/projects/fb2/node_modules/connect/lib/middleware/router.js:191:10)
at Object.router [as handle] (/home/eugene/public_html/all_things_node/projects/fb2/node_modules/connect/lib/middleware/router.js:197:6)
at next (/home/eugene/public_html/all_things_node/projects/fb2/node_modules/connect/lib/http.js:198:15)
at Object.auth [as handle] (/home/eugene/public_html/all_things_node/projects/fb2/node_modules/connect-auth/lib/index.js:153:7)
Error: Can't set headers after they are sent.
at ServerResponse.<anonymous> (http.js:527:11)
at ServerResponse.setHeader (/home/eugene/public_html/all_things_node/projects/fb2/node_modules/connect/lib/patch.js:50:20)
at next (/home/eugene/public_html/all_things_node/projects/fb2/node_modules/connect/lib/http.js:162:13)
at next (/home/eugene/public_html/all_things_node/projects/fb2/node_modules/connect/lib/http.js:150:23)
at next (/home/eugene/public_html/all_things_node/projects/fb2/node_modules/connect/lib/http.js:207:9)
at Object.auth [as handle] (/home/eugene/public_html/all_things_node/projects/fb2/node_modules/connect-auth/lib/index.js:153:7)
at next (/home/eugene/public_html/all_things_node/projects/fb2/node_modules/connect/lib/http.js:198:15)
at HTTPServer.handle (/home/eugene/public_html/all_things_node/projects/fb2/node_modules/connect/lib/http.js:211:3)
at Object.handle (/home/eugene/public_html/all_things_node/projects/fb2/node_modules/connect/lib/http.js:105:14)
at next (/home/eugene/public_html/all_things_node/projects/fb2/node_modules/connect/lib/http.js:198:15)
Error: Can't set headers after they are sent.
at ServerResponse.<anonymous> (http.js:527:11)
at ServerResponse.setHeader (/home/eugene/public_html/all_things_node/projects/fb2/node_modules/connect/lib/patch.js:50:20)
at next (/home/eugene/public_html/all_things_node/projects/fb2/node_modules/connect/lib/http.js:162:13)
at next (/home/eugene/public_html/all_things_node/projects/fb2/node_modules/connect/lib/http.js:150:23)
at next (/home/eugene/public_html/all_things_node/projects/fb2/node_modules/connect/lib/http.js:207:9)
at HTTPServer.handle (/home/eugene/public_html/all_things_node/projects/fb2/node_modules/connect/lib/http.js:211:3)
at Object.handle (/home/eugene/public_html/all_things_node/projects/fb2/node_modules/connect/lib/http.js:105:14)
at next (/home/eugene/public_html/all_things_node/projects/fb2/node_modules/connect/lib/http.js:198:15)
at /home/eugene/public_html/all_things_node/projects/fb2/node_modules/connect/lib/middleware/session.js:323:9
at /home/eugene/public_html/all_things_node/projects/fb2/node_modules/connect/lib/middleware/session.js:338:9
node.js:134
throw e; // process.nextTick error, or 'error' event on first tick
^
Error: Can't set headers after they are sent.
at ServerResponse.<anonymous> (http.js:527:11)
at ServerResponse.setHeader (/home/eugene/public_html/all_things_node/projects/fb2/node_modules/connect/lib/patch.js:50:20)
at next (/home/eugene/public_html/all_things_node/projects/fb2/node_modules/connect/lib/http.js:162:13)
at next (/home/eugene/public_html/all_things_node/projects/fb2/node_modules/connect/lib/http.js:207:9)
at /home/eugene/public_html/all_things_node/projects/fb2/node_modules/connect/lib/middleware/session.js:323:9
at /home/eugene/public_html/all_things_node/projects/fb2/node_modules/connect/lib/middleware/session.js:338:9
at Array.<anonymous> (/home/eugene/public_html/all_things_node/projects/fb2/node_modules/connect/lib/middleware/session/memory.js:57:7)
at EventEmitter._tickCallback (node.js:126:26)
The following is my code:
var fbId= "XXX";
var fbSecret= "XXXXXX";
var fbCallbackAddress= "http://127.0.0.1:8888/auth/facebook_callback"
var cookieSecret = "node"; // enter a random hash for security
var express= require('express');
var auth = require('connect-auth')
var app = express.createServer();
app.configure(function(){
app.use(express.bodyParser());
app.use(express.methodOverride());
app.use(express.cookieParser());
app.use(express.session({secret: cookieSecret}));
app.use(auth([
auth.Facebook({
appId : fbId,
appSecret: fbSecret,
callback: fbCallbackAddress,
scope: 'offline_access,email,user_about_me,user_activities,manage_pages,publish_stream',
failedUri: '/noauth'
})
]));
app.use(app.router);
});
app.get('/auth/facebook', function(req, res) {
req.authenticate("facebook", function(error, authenticated) {
if (authenticated) {
res.redirect("/great");
console.log("ok cool.");
console.log(res['req']['session']);
}
});
});
app.get('/noauth', function(req, res) {
console.log('Authentication Failed');
res.send('Authentication Failed');
});
app.get('/great', function( req, res) {
res.send('Supercoolstuff');
});
app.listen(8888);
May I know what is wrong with my code?
The res object in Express is a subclass of Node.js's http.ServerResponse (read the http.js source). You are allowed to call res.setHeader(name, value) as often as you want until you call res.writeHead(statusCode). After writeHead, the headers are baked in and you can only call res.write(data), and finally res.end(data).
The error "Error: Can't set headers after they are sent." means that you're already in the Body or Finished state, but some function tried to set a header or statusCode. When you see this error, try to look for anything that tries to send a header after some of the body has already been written. For example, look for callbacks that are accidentally called twice, or any error that happens after the body is sent.
In your case, you called res.redirect(), which caused the response to become Finished. Then your code threw an error (res.req is null). and since the error happened within your actual function(req, res, next) (not within a callback), Connect was able to catch it and then tried to send a 500 error page. But since the headers were already sent, Node.js's setHeader threw the error that you saw.
Comprehensive list of Node.js/Express response methods and when they must be called:
Response must be in Head and remains in Head:
res.writeContinue()
res.statusCode = 404
res.setHeader(name, value)
res.getHeader(name)
res.removeHeader(name)
res.header(key[, val]) (Express only)
res.charset = 'utf-8' (Express only; only affects Express-specific methods)
res.contentType(type) (Express only)
Response must be in Head and becomes Body:
res.writeHead(statusCode, [reasonPhrase], [headers])
Response can be in either Head/Body and remains in Body:
res.write(chunk, encoding='utf8')
Response can be in either Head/Body and becomes Finished:
res.end([data], [encoding])
Response can be in either Head/Body and remains in its current state:
res.addTrailers(headers)
Response must be in Head and becomes Finished:
return next([err]) (Connect/Express only)
Any exceptions within middleware function(req, res, next) (Connect/Express only)
res.send(body|status[, headers|status[, status]]) (Express only)
res.attachment(filename) (Express only)
res.sendfile(path[, options[, callback]]) (Express only)
res.json(obj[, headers|status[, status]]) (Express only)
res.redirect(url[, status]) (Express only)
res.cookie(name, val[, options]) (Express only)
res.clearCookie(name[, options]) (Express only)
res.render(view[, options[, fn]]) (Express only)
res.partial(view[, options]) (Express only)
Some of the answers in this Q&A are wrong. The accepted answer is also not very "practical", so I want to post an answer that explains things in simpler terms. My answer will cover 99% of the errors I see posted over and over again. For the actual reasons behind the error take a look at the accepted answer.
HTTP uses a cycle that requires one response per request. When the client sends a request (e.g. POST or GET) the server should only send one response back to it.
This error message:
Error: Can't set headers after they are sent.
usually happens when you send several responses for one request. Make sure the following functions are called only once per request:
res.json()
res.send()
res.redirect()
res.render()
(and a few more that are rarely used, check the accepted answer)
The route callback will not return when these res functions are called. It will continue running until it hits the end of the function or a return statement. If you want to return when sending a response you can do it like so: return res.send().
Take for instance this code:
app.post('/api/route1', function(req, res) {
console.log('this ran');
res.status(200).json({ message: 'ok' });
console.log('this ran too');
res.status(200).json({ message: 'ok' });
}
When a POST request is sent to /api/route1 it will run every line in the callback. A Can't set headers after they are sent error message will be thrown because res.json() is called twice, meaning two responses are sent.
Only one response can be sent per request!
The error in the code sample above was obvious. A more typical problem is when you have several branches:
app.get('/api/company/:companyId', function(req, res) {
const { companyId } = req.params;
Company.findById(companyId).exec((err, company) => {
if (err) {
res.status(500).json(err);
} else if (!company) {
res.status(404).json(); // This runs.
}
res.status(200).json(company); // This runs as well.
});
}
This route with attached callback finds a company in a database. When doing a query for a company that doesn't exist we will get inside the else if branch and send a 404 response. After that, we will continue on to the next statement which also sends a response. Now we have sent two responses and the error message will occur. We can fix this code by making sure we only send one response:
.exec((err, company) => {
if (err) {
res.status(500).json(err);
} else if (!company) {
res.status(404).json(); // Only this runs.
} else {
res.status(200).json(company);
}
});
or by returning when the response is sent:
.exec((err, company) => {
if (err) {
return res.status(500).json(err);
} else if (!company) {
return res.status(404).json(); // Only this runs.
}
return res.status(200).json(company);
});
A big sinner is asynchronous functions. Take the function from this question, for example:
article.save(function(err, doc1) {
if (err) {
res.send(err);
} else {
User.findOneAndUpdate({ _id: req.user._id }, { $push: { article: doc._id } })
.exec(function(err, doc2) {
if (err) res.send(err);
else res.json(doc2); // Will be called second.
})
res.json(doc1); // Will be called first.
}
});
Here we have an asynchronous function (findOneAndUpdate()) in the code sample. If there are no errors (err) findOneAndUpdate() will be called. Because this function is asynchronous the res.json(doc1) will be called immediately. Assume there are no errors in findOneAndUpdate(). The res.json(doc2) in the else will then be called. Two responses have now been sent and the Can't set headers error message occurs.
The fix, in this case, would be to remove the res.json(doc1). To send both docs back to the client the res.json() in the else could be written as res.json({ article: doc1, user: doc2 }).
I ran into this error as well for a while. I think (hope) I've wrapped my head around it, wanted to write it here for reference.
When you add middleware to connect or express (which is built on connect) using the app.use method, you're appending items to Server.prototype.stack in connect (At least with the current npm install connect, which looks quite different from the one github as of this post). When the server gets a request, it iterates over the stack, calling the (request, response, next) method.
The problem is, if in one of the middleware items writes to the response body or headers (it looks like it's either/or for some reason), but doesn't call response.end() and you call next() then as the core Server.prototype.handle method completes, it's going to notice that:
there are no more items in the stack, and/or
that response.headerSent is true.
So, it throws an error. But the error it throws is just this basic response (from the connect http.js source code:
res.statusCode = 404;
res.setHeader('Content-Type', 'text/plain');
res.end('Cannot ' + req.method + ' ' + req.url);
Right there, it's calling res.setHeader('Content-Type', 'text/plain');, which you are likely to have set in your render method, without calling response.end(), something like:
response.setHeader("Content-Type", "text/html");
response.write("<p>Hello World</p>");
The way everything needs to be structured is like this:
Good Middleware
// middleware that does not modify the response body
var doesNotModifyBody = function(request, response, next) {
request.params = {
a: "b"
};
// calls next because it hasn't modified the header
next();
};
// middleware that modify the response body
var doesModifyBody = function(request, response, next) {
response.setHeader("Content-Type", "text/html");
response.write("<p>Hello World</p>");
response.end();
// doesn't call next()
};
app.use(doesNotModifyBody);
app.use(doesModifyBody);
Problematic Middleware
var problemMiddleware = function(request, response, next) {
response.setHeader("Content-Type", "text/html");
response.write("<p>Hello World</p>");
next();
};
The problematic middleware sets the response header without calling response.end() and calls next(), which confuses connect's server.
I had this same issue and realised it was because I was calling res.redirect without a return statement, so the next function was also being called immediately afterwards:
auth.annonymousOnly = function(req, res, next) {
if (req.user) res.redirect('/');
next();
};
Which should have been:
auth.annonymousOnly = function(req, res, next) {
if (req.user) return res.redirect('/');
next();
};
Lots of people hit this error. It's a confusing this with async processing. Most likely some of your code is setting headers in the first tick and then you are running an async callback in a future tick. In between, the response header gets sent, but then further headers (like a 30X redirect) try to add extra headers, but it's too late since the response header has already been transmitted.
I'm not sure exactly what's causing your error, but look at any callbacks as potential areas to investigate.
One easy tip to simplify your code. Get rid of app.configure() and just call app.use directly in your top level scope.
See also the everyauth module, which does Facebook and a dozen or so other 3rd party authentication providers.
This type of error you will get when you pass statements after sending a response.
For example:
res.send("something response");
console.log("jhgfjhgsdhgfsdf");
console.log("sdgsdfhdgfdhgsdf");
res.send("sopmething response");
Will result in the error you are seeing, because once the response has been sent, the following res.send will not be executed.
If you want do anything, you should do it before sending the response.
error find by itself after a RND :
1) my error code :
return res.sendStatus(200).json({ data: result });
2) my success code
return res.status(200).json({ data: result });
the difference is that i used sendStatus() instead of status().
I boiled my head over this issue and it has happened due to a careless mistake on handling the callbacks. non returned callbacks cause the response to be set twice.!
My program had a code which validate request and query the DB. after validating if error is there, I was calling back the index.js with the validation errors .
And if validation passes it goes ahead and hit the db with success/failure.
var error = validateRequestDetails("create",queryReq);
if (error)
callback(error, null);
else
some code
callback(null, success);
What was happening is : Incase validation fails the callback get called and response get set. But not returned. So it still continues the method goes to db and hit success/failure . It calls the same callback again causing the response to be set twice now.
So solution is simple, you need to 'return' the callback so that the method don't continue executing, once the error has occurred and hence set the response object once
var error = validateRequestDetails("create",queryReq);
if (error)
callback(error, null);
return;
else
some code
callback(null, success);
I simply add the return keyword like:
return res.redirect("/great"); and it worked!
This error happens when you send 2 responses. For example :
if(condition A)
{
res.render('Profile', {client:client_});
}
if (condition B){
res.render('Profile', {client:client_});
}
}
Imagine if for some reason condition A and B are true so in the second render you'll get that error
Sometimes you may get this error when you try to call next() function after res.end or res.send , try to delete if you have next() after res.send or res.end in your function.
Note: here next() means after responding to the client with your response(i.e res.send or res.end) you are still trying to execute some code to respond again so it is not legal.
Example :
router.get('/',function (req,res,next){
res.send("request received");
next(); // this will give you the above exception
});
remove next() from above function and it will work.
If you are using callback functions use return after the err block. This is one of the scenarios in which this error can happen.
userModel.createUser(data, function(err, data) {
if(err) {
res.status = 422
res.json(err)
return // without this return the error can happen.
}
return res.json(data)
})
Tested on Node version v10.16.0 and express 4.16.4
there is something else that cause this error and it is when you do not add return keyword in front of res.send, res.json, etc...
Please check if your code is returning multiple res.send() statements for a single request. Like when I had this issue....
I was this issue in my restify node application. The mistake was that
switch (status) {
case -1:
res.send(400);
case 0:
res.send(200);
default:
res.send(500);
}
I was handling various cases using switch without writing break. For those little familiar with switch case know that without break, return keywords. The code under case and next lines of it will be executed no matter what. So even though I want to send single res.send, due to this mistake it was returning multiple res.send statements, which prompted
error: can't set headers after they are sent to the client.
Which got resolved by adding this or using return before each res.send() method like return res.send(200)
switch (status) {
case -1:
res.send(400);
break;
case 0:
res.send(200);
break;
default:
res.send(500);
break;
}
In my case it was a 304 response (caching) that was causing the issue.
Easiest solution:
app.disable('etag');
Alternate solution here if you want more control:
http://vlasenko.org/2011/10/12/expressconnect-static-set-last-modified-to-now-to-avoid-304-not-modified/
For anyone that's coming to this and none of the other solutions helped, in my case this manifested on a route that handled image uploading but didn't handle timeouts, and thus if the upload took too long and timed out, when the callback was fired after the timeout response had been sent, calling res.send() resulted in the crash as the headers were already set to account for the timeout.
This was easily reproduced by setting a very short timeout and hitting the route with a decently-large image, the crash was reproduced every time.
In my case this happened with React and postal.js when I didn't unsubscribe from a channel in the componentWillUnmount callback of my React component.
Just leaned this. You can pass the responses through this function:
app.use(function(req,res,next){
var _send = res.send;
var sent = false;
res.send = function(data){
if(sent) return;
_send.bind(res)(data);
sent = true;
};
next();
});
This happens when response was delivered to client and again you are trying to give response. You have to check in your code that somewhere you are returning response to client again which causes this error. Check and return response once when you want to return.
Please search if in your app.get to not set status before res.send("your result");
I just removed :
res.sendStatus(200);
and response works after that !!!
res.send("your result");
A newer version of Node supports res.headersSent boolean expression. You can use it to validate whether you already sent a response:
if (!res.headersSent) // if doesn't sent yet
res.status(200).send({ "message": "This is a message" })
Note! Although this works and answers the question, it's not the right way to solve the problem, and is not recommended!
Sending a response more than once indicates that you have a problem in your code that should be fixed (It's the same as using two return statements, one after another, in your function. it's a bug).
Add this middlware and it will work
app.use(function(req,res,next){
var _send = res.send;
var sent = false;
res.send = function(data){
if(sent) return;
_send.bind(res)(data);
sent = true;
};
next();
});
If you din't get help from above : for noobs
The reason behind this error is sending request multiple times let us understand from some cases:-
1. `
module.exports = (req,res,next)=>{
try{
const decoded = jwt.verify(req.body.token,"secret");
req.userData = decoded;
next();
}catch(error){
return res.status(401).json({message:'Auth failed'});
}
next();
}
`
in the above calling next() twice will raise an error
router.delete('/:orderId', (req, res, next) => {
Order.remove({_id:req.params.orderId},(err,data)=>{
if(err){
**res.status(500).json(err);**
}else{
res.status(200).json(data);
}
*res.status(200).json(data);*
})
})
here respond is send twice check whether you already sent a response
It is very likely that this is more of a node thing, 99% of the time it's a double callback causing you to respond twice, or next()ing twice etc, damn sure. It solved my problem was using next() inside a loop. Remove the next() from the loop or stop calling it more than one times.
If you uses two of res.end() function in one api call, this error shows
for example
app.post("/auth", function (request, res) {
var username = request.body.username;
var password = request.body.password;
if (username && password) {
let sql =
"SELECT username, worker_name, worker_surname, id FROM workers where username = ? AND password=?";
con.query(sql, [username, password], function (error, results, fields) {
if (results.length > 0) {
res.status(200).send(results);
res.end();
}
res.status(404).send("Incorrect Username and/or Password!");
});
} else {
res.send("Please enter Username and Password!");
}
res.end();
});
sometimes only writing
res.status(200).json({success: 'user authenticated');
is not enough.
For hours , i found we have to return return response sometimes.
Like this
return res.status(200).json({success: 'user authenticated');
so that It can terminate whenever in some conditional statement and doesn't run other .
The problem was exist from /auth/facebook route to make things ease to understand, once that you sent a response already from the client, you must NOT set any other functions below for next successor block, it is also related on being Synchronous of JavaScript,
for deep understanding, it is looks like this code;
async function getRequest(){
let data = await API.get();
return data;
let json = data.json(); // will not read this line
}
on your case, console.log("ok cool."); and console.log(res['req']['session']) must be put before res.redirect("/great")
Hope it make sense, Welcome :)
I had the same issue. For me i had 2 res.json(event) was giving this error to me.
res.json(savedEvent);
res.json({ event });
We should pass only single response will work.
res.json(event);
I got a similar error when I tried to send response within a loop function. The simple solution was to move the
res.send('send response');
out of the loop since you can only send response header once.
https://www.tutorialspoint.com/nodejs/nodejs_response_object.htm
Check your code. For me, I used res.status twice in the same if statement. First one set the header status and the second one tried to change it, which caused the problem.

How to handle callback error in node.js

I am new to node.js, I have a requirement where i am trying to handle the error that is being returned from the callback method/function. How do i assign the error that is being sent as part of callback to my response payload.
The node module that i am calling to validate swagger supports both callback function as well as Promise.
So how do i assign the err to my response payload. Currently i am just logging to my console, but since we plan to expose this through an API i would like to return the error information in the response payload.
var express = require('express');
var SwaggerParser = require('swagger-parser');
var myParser = require("body-parser");
var app = express();
var fs = require("fs");
app.use(myParser.urlencoded({extended : true}));
app.use(myParser.json());
function errorHandler (err, req, res, next) {
res.status(500)
res.render('error', { error: err })
}
app.post('/v1/swagger/validate',function(request,response){
/**SwaggerParser.validate(request.body, function(err, api) {
if (err) {
console.error(err);
console.log("Inside Error");
}
else {
console.log("API name: %s, Version: %s", api.info.title, api.info.version);
console.log("Inside Success");
}
}); **/
SwaggerParser.validate(request.body)
.then(function(api) {
console.log("API name: %s, Version: %s", api.info.title, api.info.version);
})
.catch(function(err) {
console.error(err);
});
response.end();
});
app.listen(8082);
You can decide how you want to communicate the error back from your API.
If the error is internal to your server and not something caused directly by a poor API request, then you probably return a 500 status code (internal server error).
response.status(500).end();
If there's something meaningful to communicate back to the other end of the API (like nothing found for the query or a specific validation error), then you have to design what you want that to be. For example, you could be sending back some JSON:
response.json({result: null, msg: "Validation Failed"});
So, it's really up to you what you want your API to return for a given situation. The main point is that you decide what you want that response to be and you send it as the response, even in error conditions. You need to make it a design that makes sense to the consumers of your API so they can clearly tell when they have a proper result and clearly tell when they have an error and if the error is their fault they need to be able to tell why it is their fault based on the response (so they more detail you provide on the issue in the response, the better).

How to send a custom http status message in node / express?

My node.js app is modeled like the express/examples/mvc app.
In a controller action I want to spit out a HTTP 400 status with a custom http message.
By default the http status message is "Bad Request":
HTTP/1.1 400 Bad Request
But I want to send
HTTP/1.1 400 Current password does not match
I tried various ways but none of them set the http status message to my custom message.
My current solution controller function looks like that:
exports.check = function( req, res) {
if( req.param( 'val')!=='testme') {
res.writeHead( 400, 'Current password does not match', {'content-type' : 'text/plain'});
res.end( 'Current value does not match');
return;
}
// ...
}
Everything works fine but ... it seems not the the right way to do it.
Is there any better way to set the http status message using express ?
None of the existing answers accomplish what the OP originally asked for, which is to override the default Reason-Phrase (the text appearing immediately after the status code) sent by Express.
What you want is res.statusMessage. This is not part of Express, it's a property of the underlying http.Response object in Node.js 0.11+.
You can use it like this (tested in Express 4.x):
function(req, res) {
res.statusMessage = "Current password does not match";
res.status(400).end();
}
Then use curl to verify that it works:
$ curl -i -s http://localhost:3100/
HTTP/1.1 400 Current password does not match
X-Powered-By: Express
Date: Fri, 08 Apr 2016 19:04:35 GMT
Connection: keep-alive
Content-Length: 0
You can check this res.send(400, 'Current password does not match')
Look express 3.x docs for details
UPDATE for Expressjs 4.x
Use this way (look express 4.x docs):
res.status(400).send('Current password does not match');
// or
res.status(400);
res.send('Current password does not match');
You can use it like this
return res.status(400).json({'error':'User already exists.'});
One elegant way to handle custom errors like this in express is:
function errorHandler(err, req, res, next) {
var code = err.code;
var message = err.message;
res.writeHead(code, message, {'content-type' : 'text/plain'});
res.end(message);
}
(you can also use express' built-in express.errorHandler for this)
Then in your middleware, before your routes:
app.use(errorHandler);
Then where you want to create the error 'Current password does not match':
function checkPassword(req, res, next) {
// check password, fails:
var err = new Error('Current password does not match');
err.code = 400;
// forward control on to the next registered error handler:
return next(err);
}
At server side(Express middleware):
if(err) return res.status(500).end('User already exists.');
Handle at Client side
Angular:-
$http().....
.error(function(data, status) {
console.error('Repos error', status, data);//"Repos error" 500 "User already exists."
});
jQuery:-
$.ajax({
type: "post",
url: url,
success: function (data, text) {
},
error: function (request, status, error) {
alert(request.responseText);
}
});
When using Axios you can retrieve the custom response message with:
Axios.get(“your_url”)
.then(data => {
... do something
}.catch( err => {
console.log(err.response.data) // you want this
})
...after setting it in Express as:
res.status(400).send(“your custom message”)
My use-case is sending a custom JSON error message, since I'm using express to power my REST API. I think this is a fairly common scenario, so will focus on that in my answer.
Short Version:
Express Error Handling
Define error-handling middleware like other middleware, except with
four arguments instead of three, specifically with the signature (err,
req, res, next). ... You define error-handling middleware last, after
other app.use() and routes calls
app.use(function(err, req, res, next) {
if (err instanceof JSONError) {
res.status(err.status).json({
status: err.status,
message: err.message
});
} else {
next(err);
}
});
Raise errors from any point in the code by doing:
var JSONError = require('./JSONError');
var err = new JSONError(404, 'Uh oh! Can't find something');
next(err);
Long Version
The canonical way of throwing errors is:
var err = new Error("Uh oh! Can't find something");
err.status = 404;
next(err)
By default, Express handles this by neatly packaging it as a HTTP Response with code 404, and body consisting of the message string appended with a stack trace.
This doesn't work for me when I'm using Express as a REST server, for example. I'll want the error to be sent back as JSON, not as HTML. I'll also definitely not want my stack trace moving out to my client.
I can send JSON as a response using req.json(), eg. something like req.json({ status: 404, message: 'Uh oh! Can't find something'}). Optionally, I can set the status code using req.status(). Combining the two:
req.status(404).json({ status: 404, message: 'Uh oh! Can't find something'});
This works like a charm. That said, I find it quite unwieldy to type every time I have an error, and the code is no longer self-documenting like our next(err) was. It looks far too similar to how a normal (i.e, valid) response JSON is sent. Further, any errors thrown by the canonical approach still result in HTML output.
This is where Express' error handling middleware comes in. As part of my routes, I define:
app.use(function(err, req, res, next) {
console.log('Someone tried to throw an error response');
});
I also subclass Error into a custom JSONError class:
JSONError = function (status, message) {
Error.prototype.constructor.call(this, status + ': ' + message);
this.status = status;
this.message = message;
};
JSONError.prototype = Object.create(Error);
JSONError.prototype.constructor = JSONError;
Now, when I want to throw an Error in the code, I do:
var err = new JSONError(404, 'Uh oh! Can't find something');
next(err);
Going back to the custom error handling middleware, I modify it to:
app.use(function(err, req, res, next) {
if (err instanceof JSONError) {
res.status(err.status).json({
status: err.status,
message: err.message
});
} else {
next(err);
}
}
Subclassing Error into JSONError is important, as I suspect Express does an instanceof Error check on the first parameter passed to a next() to determine if a normal handler or an error handler must be invoked. I can remove the instanceof JSONError check and make minor modifications to ensure unexpected errors (such as a crash) also return a JSON response.
If your goal is just to reduce it to a single/simple line, you could rely on defaults a bit...
return res.end(res.writeHead(400, 'Current password does not match'));
Well in the case of Restify we should use sendRaw() method
Syntax is:
res.sendRaw(200, 'Operation was Successful', <some Header Data> or null)

Resources