17

My understanding for the "right" way to make a custom Error class in JavaScript is something like this:

function MyError(message) {  
    this.name = "MyError";  
    this.message = message || "Default Message";  
}  
MyError.prototype = new Error();  
MyError.prototype.constructor = MyError;

(Code snippet mooked from https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Error.)

With NodeJS, if I try to check for an error of this type like:

var err = new MyError("whoops");
assert.ifError(err);

...the backtrace will show the context of the Error object I created at compile time to be the prototype for MyError, not the MyError object I created with "new MyError()".

Is there some way that I can get the correct backtrace data for the actual error, rather than the prototype?

Evan P.
  • 979
  • 1
  • 10
  • 17
  • You might be seeing the symptoms of a bug in V8: http://code.google.com/p/chromium/issues/detail?id=60240 Or perhaps this one: http://code.google.com/p/chromium/issues/detail?id=99341 – Daniel Dickison Dec 10 '11 at 18:59
  • 1
    I think I might have found how to do this: http://code.google.com/p/v8/wiki/JavaScriptStackTraceApi – Evan P. Dec 10 '11 at 19:42
  • Setting the prototype to a new Error is quite nasty because it means that useful features like stack traces will be set to that line rather than the line you actually want. – kybernetikos Oct 02 '12 at 09:54

2 Answers2

38

We need to invoke the super function - captureStackTrace

var util = require('util');

function MyError(message) {
  Error.call(this); //super constructor
  Error.captureStackTrace(this, this.constructor); //super helper method to include stack trace in error object

  this.name = this.constructor.name; //set our function’s name as error name.
  this.message = message; //set the error message
}

// inherit from Error
util.inherits(MyError, Error);

UPDATE:

You can use this node module to extend Error types easily https://github.com/jayyvis/extend-error

Jay Kumar
  • 1,514
  • 1
  • 14
  • 17
3

@Jay Kumar, has one good answer here. However, maybe here is another similar solution here

module.exports = function CustomError(message, extra) {
  Error.captureStackTrace(this, this.constructor);
  this.name = this.constructor.name;
  this.message = message;
  this.extra = extra;
};

require('util').inherits(module.exports, Error);

Error.call(this) - creates another error object (wasting a bunch of time) and doesn't touch this at all

Since the ECMAScript6 could be supported in the latest Node.js version. The answer under ES6 could be refer to this link.

class MyError extends Error {
  constructor(message) {
    super(message);
    this.message = message;
    this.name = 'MyError';
  }
}

Here are test codes under Node v4.2.1

class MyError extends Error{
        constructor(msg, extra) {
                super(msg);
                this.message = msg;
                this.name = 'MyError';
                this.extra = extra;
        }
};

var myerr = new MyError("test", 13);
console.log(myerr.stack);
console.log(myerr);

Output:

MyError: test
    at MyError (/home/bsadmin/test/test.js:5:8)
    at Object.<anonymous> (/home/bsadmin/test/test.js:12:13)
    at Module._compile (module.js:435:26)
    at Object.Module._extensions..js (module.js:442:10)
    at Module.load (module.js:356:32)
    at Function.Module._load (module.js:311:12)
    at Function.Module.runMain (module.js:467:10)
    at startup (node.js:134:18)
    at node.js:961:3
{ [MyError: test] name: 'MyError', extra: 13 }
zangw
  • 43,869
  • 19
  • 177
  • 214