I had some problematic code in a Node.js application which caused an error (manifested as strange output) but not a total crash. It displayed nothing in the console to indicate an error occurred, and I only identified the root cause by a lot of trial and error in commenting out lines selectively.
To save time in future, is there anything like Java's UncaughtExceptionHandler in Node that will catch anything that's causing errors and display them in the console so I can pinpoint bug(s) immediately?
Yes. You can listen for that event by doing this
process.on('uncaughtException', (err) => {
});
It will override the default behaviour of exiting.
Documentation
And actually, I don't fully understand why my code is not in the stack trace, if node is single threaded. Maybe I'm fundamentally misunderstanding, something, but why does my application sometimes die with a stack trace that doesn't have anything I've written in it?
I'm writing a pretty simple proxy server using node/express. As an example, I was periodically getting this "socket hangup error":
Error: socket hang up
at createHangUpError (_http_client.js:250:15)
at Socket.socketOnEnd (_http_client.js:342:23)
at emitNone (events.js:91:20)
at Socket.emit (events.js:185:7)
at endReadableNT (_stream_readable.js:926:12)
at _combinedTickCallback (internal/process/next_tick.js:74:11)
at process._tickCallback (internal/process/next_tick.js:98:9) code: 'ECONNRESET' }
And since none of the javascript files in the stack trace are mine, I had no idea where this was coming from. It was basically trial and error, trying to catch errors and adding .on style error-handlers until I found the right place.
I feel like I'm fundamentally missing something - what I should I be doing differently in order to debug errors like this? How do I know where to handle it if I can't see what (in my code) is causing it? How do I know whether I should be using a try/catch block, or something like request.on('error') {...}?
Some errors, like the one mentioned by you, are not caused by your code. In fact it is caused by the absence of code in your application. (For example, your application code is probably missing the code for gracefully handling ECONNRESET i.e. remote socket disconnection.
Now, to your question about how to debug such errors (including third-party code). Of course, you can use stack-trace and longjohn etc.
But, for me, the easier & quicker solution is to run the application in debug mode with --inspect option, with Chrome debugger to inspect it (no breakpoints), with Pause on Exceptions option enabled. That's all you need to do. Now whenever there is an exception, chrome debugger will pause the application exactly at the line where the exception is thrown. Makes it a lot easier to find such bugs.
Hope this helps you!
You could do something like for debugging such errors.
process.on('uncaughtException', function(err) {
console.log(err.stack);
throw err;
});
You could also increase your stack trace size limit and/or stack size.
node --stack_trace_limit=200 app.js //defaults to 10
node --stack-size=1024 app.js // defaults to 492kB
Contrary to your assumption, the single thread paradigm of node.js cause these types of error. In a multi-thread environment like java, all the called functions are executed inside the caller function:
java -> A -> B -> C -> D
So if the A() is wrapped in a try and catch all the internal exceptions are caught.
But in Async environment, the callback function is executed outside the caller function:
node -> A -> B(C)
node -> I -> C -> D
Here the function A call async function B (Usually a library) with callback function C as an argument, function B start an async task after it's finished node.js call function I which is an internal function of that library and it calls function C. Here you see I, C and D are called outside of your code.
So there are two things to consider here:
1- you must wrap your callback function code in try and catch.
2- there may be an exception in function I which you can not catch in your code. These are those exceptions that you are referring which none of the javascript files in the stack trace are yours because it's not initiated in your code.
Now if the function B (its library) is good written it must provide some means to catch those exceptions. One of them would be on('error', cb). So you should always check the library documentation to see how you can catch and handle such exceptions.
If the library is poorly written and nothing is provided to catch its exceptions in your code, you can use a debugger like chrome inspector or WebStorm debugger to catch them but there is no other way than manipulating its source code so at least they are bypassed to your code, or you can file a bug report.
Node.js also provide an uncaught exception handler which catches all uncaught exceptions:
process.on('uncaughtException', (err) => {
process.exit(1);
});
although it's risky to continue execution after here because things could be in an uncertain state, but it's a good place to log errors.
Stack Trace does not contain your file because this type of error is created server connection issue like:
Host Timeout
[ 'code' ]
e.code => ECONNRESET
Console output
{ Error: socket hang up
at createHangUpError (_http_client.js:250:15)
at TLSSocket.socketCloseListener (_http_client.js:282:23)
at emitOne (events.js:101:20)
at TLSSocket.emit (events.js:188:7)
at TCP._handle.close [as _onclose] (net.js:492:12) code: 'ECONNRESET' }
OR when the server terminates the connection unexpectedly or does not send a response.
For more info check node app error codes.
or refer to this issue.
You might try the built in debugger for node.js. This debugger allows you to step through code that is not yours.
node debug script.js
Another good tool is node-inspector.
This article has some other debug options that could be useful in determining the cause of your exception: How do I debug Node.js applications?
Looking for ideas on how to debug an app that is crashing randomly without being caught by:
process.on('uncaughtException', function(err){});
I've also had no luck trying Winston (the log file remains empty) to catch whatever is causing the app to crash:
winston.handleExceptions(new winston.transports.File({ filename: 'exceptions.log' }))
What kind of program faults can even get past these?
It isn't pretty but the following was enough to do the job for me:
setInterval(function(){winston.logger.info(moment().format('YYYY-MM-DD HH:mm:ss.SSS')+' ' + process.memoryUsage().rss)}, dt_timer);
Also, one answer to the question regarding what type of program fault can crash a node app that is handling 'uncaughtException' - Memory Leaks!
Cheers.
I have a node.js project that is using mocha for it's testing. My most recent test that utilizes Sequelizes create() function for adding a row to a table now produces this message instead of the stack trace that I have always seen up until now...
1) Should be able to store a player's name
^--- With additional stack trace: Error: [object SequelizeInstance]
I am unable to find any additional stack trace info. The log files contain no information. Any idea why this is occurring, and how I can view the stack trace?
Error: [object SequelizeInstance] to me says that somewhere you are doing new Error(result). The simplest way that could happen is if you have a callback like
function(err, result){
that is actually supposed to be
function(result){
so I would check your callbacks and ensure that they all actually match the expected signature. Most callbacks in node use the two-param format, but not all.
I wrote a node program to scrape url content. Since a lot of things get thrown into and out the machine, I have a process listener for uncaughtException and just throw the error results into a log file instead of letting it kill the daemon. Going over that log file recently, I noticed something amiss. Here's an error that gets thrown frequently and the stack trace:
Stack Trace:
ReferenceError: GEL is not defined
at Object._onTimeout
(http://www.freep.com/article/20110809/ENT04/110809051/1001/news:undefined:undefined:2:25)
at Timer.callback (timers.js:83:39)
Not very informative I know. Naturally, I rgrepped my source code for GEL. Then I rgrepped all my node module dependencies (there's not that many) for GEL. Then I rgrepped node for GEL. Then I rgrepped v8 for GEL. Then I stopped and asked StackOverflow... What am I doing wrong? (I'm not doing anything too unreasonable in my code like trying to eval random strings or whatnot.)
Important: node v 0.4.9 ... think it also gets thrown on v 0.4.10
I figured out the problem. It was in fact my code's fault. The code I was debugging was using the jsdom module, which was interpreting the javascript from the web pages I was scraping. I fixed the problem I was having by improving my regex that strips out <script> tags and passed an extra features argument to my jsdom.env call:
jsdom.env({
html: myHtml,
done: myCallback,
url: url,
features : {
FetchExternalResources : [],
ProcessExternalResources : false
}
});