Non existing property: EventEmitter memory error instead of proper error message

Viewed 234

In a NodeJS 6.10.2/SailsJS 0.12.13 based JavaScript application I experience since several months a strange error behavior.

In a Sails controller, I try to retrieve a property of a literal object:

console.log(someObject.someProperty);
console.log("I am still here!");

However, in my case someObject is undefined. So, I'd expect to get an error like 'Cannot read property someProperty of undefined.' - and then either Node.js to stop completely or the code to go on (with the next console.log).

Instead, the code simply stops executing at that point and I get a strange warning: "(node:4822) Warning: Possible EventEmitter memory leak detected. 11 close listeners added. Use emitter.setMaxListeners() to increase limit." It is however, unpredictable how often this error occurs. Somethings only once, somethings about 20 times right after each other.

What I found out so for is that it is somehow connected to the question whether there was already a response or not. Consider the following:

mySailsControllerFunction: function(req, res) {
    console.log(someObject.someProperty);
    console.log("I am still here!");
    res.json({"foo":"dahoo"});
   }

This will result in Sending 500 ("Server Error") response: ReferenceError: someObject is not defined - exactly what I expect.

However, now I first send some response and then trying to access my non existing property, turning the code into:

mySailsControllerFunction: function(req, res) {
        res.json({"foo":"dahoo"});
        setTimeout(function () {
          console.log("Yeah!");
          console.log(someObject.someProperty);
          console.log("I am still here!");
       },1000);
}

then I often get simply nothing: 'Yeah!' displayed, but nothing comes afterwards. The event listener error is sometimes there, sometimes not. Very strange.

Additionally, and strange enough, the problem seems to be somehow connected to the time passed since the start of Sails. I put the code you see above inside a Sails controller function which is called immediately after the clients re-connect. I then played around with the timeout values, restarting the Sails server several times. Outcome: If I set the timeout to 1s, in 4 of 5 tests, I will get the correct error behavior. For 10 seconds it is about 50%, for 30s the error will always be ignored without any console output.

However, if I put my test code outside of the Sails controller, I always get the correct error behavior by Node. So, I'm quite sure this is a wrong behavior of Sails, not Node.

2 Answers

For reference: I finally solved that issue. There were, somehow hidden in the code, process exit handlers defined:

 process.on('exit', myErrorFunction.bind());
 process.on('SIGINT', myErrorFunction.bind());
 process.on('uncaughtException', myErrorFunction.bind());

The problem was: The function in which these lines were in was bound to a cronjob. So, each time the cronjob executed, new handlers were registered. So, my assumption above (before vs. after response) was wrong: In fact everything worked till the cronjob was executed for the first time. From then on, it didn't. And eventually, the warning was fired (correctly!).

I would have never found out without this answer: Make node show stack trace after EventEmitter warning You have to add one line of code to get the stack trace:

process.on('warning', e => console.warn(e.stack));

Additionally, speaking of stack traces: In the Sails serverError response (api/api/responses/serverError.js), it is convenient to access it like this:

module.exports = function serverError (data, options) {
  console.log(data.stack);
  /* ... */
};
Related