Skip to content

Can't set headers after they are sent.] Error: Can't set headers after they are sent. 2.2.18 #2580

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
gateway opened this issue Aug 24, 2016 · 22 comments

Comments

@gateway
Copy link

gateway commented Aug 24, 2016

Please read the following instructions carefully.

Check out #1271 for an ideal bug report.
The closer your issue report is to that one, the more likely we are to be able to help, and the more likely we will be to fix the issue quickly!

Many members of the community use Stack Overflow and Server Fault to ask questions.
Read through the existing questions or ask your own!

For database migration help, please file a bug report at https://parse.com/help#report

Make sure these boxes are checked before submitting your issue -- thanks for reporting issues back to Parse Server!

Issue Description

While looking into a cloud code issue which I fixed, I saw this issue in my Heroku logs and Parse Dashboard logs.. I have no idea what this could be but doesnt sound to good.

Not sure how to debug this, but needed to provide this to the community.

I should note rolling back to 2.2.17 this does not happen.. :/

2016-08-24T18:17:46.973Z - Uncaught internal server error. [Error: Can't set headers after they are sent.] Error: Can't set headers after they are sent.
    at ServerResponse.OutgoingMessage.setHeader (_http_outgoing.js:346:11)
    at ServerResponse.header (/app/node_modules/express/lib/response.js:695:10)
    at allowCrossDomain (/app/node_modules/parse-server/lib/middlewares.js:229:7)
    at Layer.handle [as handle_request] (/app/node_modules/parse-server/node_modules/express/lib/router/layer.js:95:5)
    at next (/app/node_modules/parse-server/node_modules/express/lib/router/route.js:131:13)
    at Route.dispatch (/app/node_modules/parse-server/node_modules/express/lib/router/route.js:112:3)
    at Layer.handle [as handle_request] (/app/node_modules/parse-server/node_modules/express/lib/router/layer.js:95:5)
    at /app/node_modules/parse-server/node_modules/express/lib/router/index.js:277:22
    at param (/app/node_modules/parse-server/node_modules/express/lib/router/index.js:349:14)
    at param (/app/node_modules/parse-server/node_modules/express/lib/router/index.js:365:14)

Environment Setup

  • Server
    • parse-server version (Be specific! Don't say 'latest'.) : 2.2.18
    • Operating System: Heroku Dyno
    • Hardware: Heroku Dyno
    • Localhost or remote server? (AWS, Heroku, Azure, Digital Ocean, etc): Heroku Dyno
  • Database
    • MongoDB version: 3.2
    • Storage engine: WiredTiger
    • Hardware: M1 Cluster
    • Localhost or remote server? (AWS, mLab, ObjectRocket, Digital Ocean, etc): Heroku
@GuichiZhao
Copy link

GuichiZhao commented Aug 25, 2016

My workaround is never putting any route after /parse route even the 404 route .Put all the other routes before /parse instead, for 404 just exclude /parse

@flovilmart
Copy link
Contributor

@gateway what HTTP call trigger that? In 2.2.18 this should have probably been fixed for most of the calls, as well as by #2559

@gateway
Copy link
Author

gateway commented Aug 25, 2016

I think this happens when our client saves a userTag, stuff they tag in our app..

This happens on a few of our queries for POST from our app..

2016-08-25T17:34:32.327145+00:00 heroku[router]: at=info method=POST path="/parse/classes/Activity" host=xxx.herokuapp.com request_id=b6a0ec3d-876f-47a8-899e-8e0ff424714c fwd="12.215.39.106" dyno=web.1 connect=1ms service=1297ms status=200 bytes=58972
2016-08-25T17:35:40.593366+00:00 app[web.1]: error: Uncaught internal server error. [Error: Can't set headers after they are sent.] Error: Can't set headers after they are sent.

@jcampalo
Copy link

Did you try to update express to latest version?

@anhldbk
Copy link

anhldbk commented Aug 30, 2016

@GuichiZhao Would you pls show me your workaround code?

@GuichiZhao
Copy link

GuichiZhao commented Aug 30, 2016

@anhldbk
index.js

//Parse use an ancient version of express,that is how we mount path
require('cloud/routes')(app)
//mount parse-dashboard application to /dashboard
app.use('/dashboard', dashboard);
//mount parse api to /parse
app.use('/parse',api);

cloud/routes/index.js

module.exports=function (app) {
    //other routes
    app.use()
    //404 catcher
    app.all(/^\/(?!parse|dashboard).*$/, function (req, res, next) {
    });
}

@anhldbk
Copy link

anhldbk commented Aug 30, 2016

@GuichiZhao Thanks.

@anhldbk
Copy link

anhldbk commented Aug 30, 2016

@flovilmart When will your patches available in npm?

@kronos
Copy link

kronos commented Aug 30, 2016

Same here. express 4.14.0

@flovilmart
Copy link
Contributor

The fix (that will probably land in 2.2.19) is intended to fix the internal problems with 'Cannot set headers' errors. For you, that use a custom express installation, you should stick with the workaround.

@mcclaskiem
Copy link

@kronos so updating to 4.14.0 fixed this for you?

@kronos
Copy link

kronos commented Aug 30, 2016

@mcclaskiem No. I meant that the problem is reproducible with the latest express

@sebastiankade
Copy link

sebastiankade commented Aug 30, 2016

Hey guys,

I wanted to upgrade to 2.2.18 for the mongo connection improvements and ran into this issue as well.

After digging into it I found that it was because of #2338 (this commit). The change was added to allow "developers to add express handlers for successful completion of parse-server requests" however this causes problems for anyone who uses Parse Server in an existing Express app like this:
app.use('/parse', new ParseServer({...}));

Why it is breaking is that by adding the next() calls to the PromiseRouter the request gets passed down onto the next app.use(), which might try to handle it again causing the "Can't set headers after they are sent" issue to arise.

The correct workaround for doing this atm is to add a callback that stops the propagation:

app.use('/parse', new ParseServer({...}), function(req, res, next) {
    // This will get called after every parse request 
    // and stops the request propagation by doing nothing
});

I don't think next() should be called inside the PromiseRouter as the whole point of an Express middleware is that if it handles a request it stops the propagation of the request. I think to solve the needs put forward in #2338 there could be a callback in the ParseServer options for this (a request callback).

👍

@flovilmart
Copy link
Contributor

I ageee with your workaround, and it should be added onto the Parse-server-example repository (PR are welcome).

When using though the CLI / standalone, we should not yield any headers already sent, internally, as we manage our routes.

On another note, calling next after the response is sent is also an opportunity to cleanup stuff (like caches) after the response is sent.

It's also an opportunity to do request tracing, logging etc.. (as it's been intended by the commit you point out).

There is nothing in the express design that prevents having 'post' middlewares, and they can be quite useful.

For now, it's been decided that next call was here to stay, there are numerous was to work around that.

On another note, adding pre middlewares can have even worse side effects, like a json body parser would conflict with the files endpoint.

@sebastiankade
Copy link

This is not a middleware though (by definition something that sits inbetween the start of the request and the handler). This IS the handler. This makes routing messy.

In node if you wanted to do things like request tracing & logging, wouldn't you generally do the following:

app.use('/parse', function(req, res, next) {
    // Do PRE work
    next();
    // Do POST work
});

In our case it would be:

var parse = new ParseServer({...});
app.use('/parse', function(req, res, next) {
    req.on('response', function() {
        // Track anything on response, such as resp time
    });

    // Manually invoke the parse server router
    parse(req, res, next);

    // Immediate POST tracing etc
});

I disagree but fair enough 👍 I shall keep my hack in place

@flovilmart
Copy link
Contributor

Definition of middleware is debatable as well, take django, middlewares are traversed in and out, before and after the request is processed...

@blacha, what do you think? Seems that this small commit is causing some ire.

@sebastiankade
Copy link

haha but my definition sounded so totally technical :P

@steven-supersolid
Copy link
Contributor

I would also prefer to drop the call to next() after responding now that there is a workaround provided for logging. It does seem that event handlers are the way to go with this and are an app-specific solution rather than something that should be built in to parse-server.

While it does the job, the fix in #2559 requires checking overlapping routes within route handlers so the routes are no longer as clearly defined. This fix wouldn't be required if we dropped next().

@flovilmart
Copy link
Contributor

Waiting to hear on @blacha's take on that as he provided that.

@benishak
Copy link
Contributor

benishak commented Sep 1, 2016

I had this error today when I upgrade to node to 6.4.0 then I tried to downgrade back to 4.5 but still get the same error.
The solution was to delete the wohle node app and redeploy it again. I use pm2 and could be that pm2 load some files from 'shared' directory while keeping it not sync with the 'source' directory. I don't know how but this solved the problem.

rm -rf myapp
# from your machine
pm2 deploy ecosystem.json myenv setup
pm2 deploy myenv

@flovilmart
Copy link
Contributor

Fixed with 2.2.19

@flovilmart
Copy link
Contributor

We've added unit tests to make sure the next() handlers are never yieled, probably you have a next(err) handler

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

10 participants