Sending JSON error from Node.js backend to iPhone frontend: "Error: Can't set headers after they are sent."

I'm new to Node.js. I'm using it as a server backend to an iPhone client. I'm calling a POST with the JSON: {firstname: "bob", email : bob@someemail.com}

The node.js code looks like this (using Express and Mongoose):

var User = new Schema({
    firstname   : { type: String, required: true}
    , email     : { type: String, required: true, unique : true}

});
var User = mongoose.model('User', User);

And for the POST,

app.post('/new/user', function(req, res){

    // make a variable for the userData
    var userData = {
        firstname: req.body.firstname,
        email: req.body.email
    };

    var user = new User(userData);

    //try to save the user data
    user.save(function(err) {
        if (err) {
            // if an error occurs, show it in console and send it back to the iPhone
            console.log(err);
            res.json(err);
        }
        else{
            console.log('New user created');
        }
    });

    res.end();
}); 

Right now, I'm trying to create duplicate users with the same email. I expect this to throw an error due to the "unique" constraint I have on the email -- which it does.

However, the node.js process dies with, "Error: Can't set headers after they are sent."

I would like to be able to send a message back to the iPhone client in scenarios such as these. For example, in the above, I'd like to be able to send back JSON to the iphone saying the result of the new user creation (successful or failed).

Thank you!

It's because the asynchronous nature of your code. The res.end() runs before the callback function of user.save you should put the res.end()inside that callback ( at the end).

this way:

  user.save(function(err) {
    if (err) {
        // if an error occurs, show it in console and send it back to the iPhone
        console.log(err);
        return res.json(err);
    }
    console.log('New user created');
    res.end();
});

Send your error using an appropriate http status, you have plenty of 4xx to do that.

 res.json(420, err);

That way, you will just have to parse the message in your http fetch, with jquery it gives something like :

jQuery.ajax({
  ...
  error: function (xhr, ajaxOptions, thrownError) {
    if(xhr.status == 420) {
      JSON.parse(xhr.responseText);
    }
  }