Codepath

Debugging

Error Handling

Error

Use the Error constructor to create errors:

let error = new Error('Some message')

When creating new errors, always be certain to maintain a reference to the original error:

try {
    // ...
} catch(e) {
    let err = new Error('User friendly message...')
    err.originalError = e
    throw err
}

throw

Anything can be thrown (String, undefined, null, Buffer), but use the Error constructor to ensure it has a stack trace:

throw new Error('Some message...')

try/catch

Use try and catch in async functions just as you would in synchronous code:

async ()=>{
  try {
    // asynchronous code here
  } catch(e) {
    console.log(e.stack)
  }
}()

.catch(err =>{})

By default, a Promise catches errors and fails silently unless you await the Promise or add .catch((err) => {}):

Example:

// USE CATCH HERE
main().catch(e => console.log(e.stack)

async function main() {
    // NOT HERE (awaiting on rejected promises throws)
    await myAsync()
}

Note: .catch((err) => {}) will typically only be necessary in the main/bootstrap file

uncaughtException and unhandledRejection

IMPORTANT: These 2 event handlers should be added at the beginning of every new project.

Node provides 2 events on process for dealing with uncaught exceptions and unhandled Promise rejections that would otherwise fail silently:

process.on('uncaughtException', function(err) {
    console.log('uncaughtException: \n\n', err.stack)
    // IMPORTANT: Exit the process (optionally, soft exit)
    process.exit()
})

process.on('unhandledRejection', (err, rejectedPromise) => {
    console.log('unhandledRejection: \n\n', err.stack)
})

See here, for details on why you should exit the process on uncaughtException.

trycatch, long-stack-traces and uncaughtApplicationException

trycatch provides 3 invaluable pieces of functionality:

  1. Wraps all non-core code in a try/catch to eliminate the need to process.exit() when errors originate in non-core code (99% of uncaughtExceptions). See the example below for how to use uncaughtApplicationException.
  2. Optional long-stack-traces. (Not recommended for production due to performance overhead)
  3. Asynchronous error catching via the trycatch function.
let trycatch = require('trycatch').configure({'long-stack-traces': true})

process.on('uncaughtApplicationException', function(err) {
    console.log('uncaughtApplicationException: \n\n', err.stack)
})

trycatch(()=> {
    setImmediate(() => {
        throw new Error("Can't catch me! I'm asynchronous!")
    })
}, (err) => {
    console.log('Oh yes I can!\n', err.stack)
})

Debuggers

node-inspector, babel-node-inspector and node-debug

Since node is built on Google Chrome's V8 JavaScript VM, Chrome Developer Tools can be utilized to live debug node code:

# Install babel-node-debug
npm install -g babel-node-debug

# Debug node code
bode-debug path/to/index.js

# Or use node-inspector directly without babel
npm install -g node-inspector
node-debug path/to/index.js

References

Fork me on GitHub