How do I create a custom Error in JavaScript?
Asked Answered
A

25

289

For some reason it looks like constructor delegation doesn't work in the following snippet:

function NotImplementedError() { 
  Error.apply(this, arguments); 
}
NotImplementedError.prototype = new Error();

var nie = new NotImplementedError("some message");
console.log("The message is: '"+nie.message+"'")

Running this gives The message is: ''. Any ideas as to why, or if there is a better way to create a new Error subclass? Is there a problem with applying to the native Error constructor that I don't know about?

Azaleeazan answered 23/4, 2009 at 22:35 Comment(8)
Does nie instanceof NotImplementedError assertion work after your changes? I thought that in order for this to work you need to define NotImplementedError.prototype.constructor explicitly.Deter
Next time, please tear out all the extraneous code that isn't required to demonstrate your issue. Also, wtc is js.jar ? Is that needed to reproduce the problem?Never
Edited this question so that its understandable in 10 seconds rather than 10 minutesNever
I created an inheritance/class library that inherits from Error types properly: github.com/fresheneesz/protoNever
exceptionsjs.com provides a NotImplementedException and other commonly used by not provided exception types. It also provides the ability to create custom exception types.Serow
jsfiddle for a few of the top answers.Dermis
Many would probably benefit from seeing #1382607Rallentando
Does this answer your question? Custom exception typeAminopyrine
T
250

Update your code to assign your prototype to the Error.prototype and the instanceof and your asserts work.

function NotImplementedError(message = "") {
    this.name = "NotImplementedError";
    this.message = message;
}
NotImplementedError.prototype = Error.prototype;

However, I would just throw your own object and just check the name property.

throw {name : "NotImplementedError", message : "too lazy to implement"}; 

Edit based on comments

After looking at the comments and trying to remember why I would assign prototype to Error.prototype instead of new Error() like Nicholas Zakas did in his article, I created a jsFiddle with the code below:

function NotImplementedError(message = "") {
  this.name = "NotImplementedError";
  this.message = message;
}
NotImplementedError.prototype = Error.prototype;

function NotImplementedError2(message = "") {
  this.message = message;
}
NotImplementedError2.prototype = new Error();

try {
  var e = new NotImplementedError("NotImplementedError message");
  throw e;
} catch (ex1) {
  console.log(ex1.stack);
  console.log("ex1 instanceof NotImplementedError = " + (ex1 instanceof NotImplementedError));
  console.log("ex1 instanceof Error = " + (ex1 instanceof Error));
  console.log("ex1.name = " + ex1.name);
  console.log("ex1.message = " + ex1.message);
}

try {
  var e = new NotImplementedError2("NotImplementedError2 message");
  throw e;
} catch (ex1) {
  console.log(ex1.stack);
  console.log("ex1 instanceof NotImplementedError2 = " + (ex1 instanceof NotImplementedError2));
  console.log("ex1 instanceof Error = " + (ex1 instanceof Error));
  console.log("ex1.name = " + ex1.name);
  console.log("ex1.message = " + ex1.message);
}

The console output was this.

undefined
ex1 instanceof NotImplementedError = true
ex1 instanceof Error = true
ex1.name = NotImplementedError
ex1.message = NotImplementedError message
Error
    at window.onload (http://fiddle.jshell.net/MwMEJ/show/:29:34)
ex1 instanceof NotImplementedError2 = true
ex1 instanceof Error = true
ex1.name = Error
ex1.message = NotImplementedError2 message

This confirmes the "problem" I ran into was the stack property of the error was the line number where new Error() was created, and not where the throw e occurred. However, that may be better that having the side effect of a NotImplementedError.prototype.name = "NotImplementedError" line affecting the Error object.

Also, notice with NotImplementedError2, when I don't set the .name explicitly, it is equal to "Error". However, as mentioned in the comments, because that version sets prototype to new Error(), I could set NotImplementedError2.prototype.name = "NotImplementedError2" and be OK.

Taejon answered 16/5, 2009 at 3:51 Comment(22)
Your object created with an object literal is not an Error so the Firefox error console (and I would assume the one in other browsers as well) won't know how to deal with it in a useful way if it's not caught. I like your first idea much better.Undertook
On the other hand, if your code is set up so that you KNOW it will be caught (because you ONLY produce that "error" in one particular function, and that function is ALWAYS wrapped in a try/catch) then maybe this is a pretty good idea.Undertook
Best answer, but taking Error.prototype directly is probably bad form. If you later want to add a NotImplementedError.prototype.toString the object now aliases to Error.prototype.toString -- better to do NotImplementedError.prototype = new Error().Azaleeazan
I know I had problem with setting prototype to new Error(), but can't remember for sure. I think that gave incorrect info for either the stack or the linenumber of the error.Taejon
I'm still a bit lost in all those prototype things. Why in your example you assign name to this.name and not to NotImplementedError.prototype.name? Can you answer please, it's crucial for my understanding :)Deter
I can't answer for Kevin, but my guess is that he does it because he sets NotImplementedError's prototype to Error.prototype, and therefore if he changed NotImplementedError.prototype's name he'd really be changing Error.prototype's name. However, if he instead set the prototype to new Error(), as cdleary suggested, that wouldn't be an issue, and it'd actually be preferable to set the name on the prototype.Misadvise
What cdleary said, see here (nczonline.net/blog/2009/03/10/…) and if possible please correct your answer.Entomologize
Also you don't need this.name for function declarations, only for unnamed function expressions. In your example, javascript engine will set name for you.Entomologize
Thanks for the comments, I updated the answer with related details.Taejon
This answer tells him how to fix the problem, but it doesn't identify why the problem exists in the first place. As of this comment, none of the answers do. I'd be very curious to find the answer.Never
Also, "assig[ning] your prototype to the Error.prototype" has nothing to do with making it work. Its all because you explicitly set the message in the NIE constructor...Never
Also you don't get a stack trace, which is kinda the important part of an exceptionNever
According to code.google.com/p/chromium/issues/detail?id=228909 subclass.prototype = new Error() is bad form. You are supposed to use subclass.prototype = Object.create(superclass.prototype) instead. I'm hoping it might fix the stack-trace problem as well.Fiberglass
@Fiberglass you might need to polyfill Object.create for some browsers, but worth a try. #13041184Taejon
Simple trick to get meaningful stacktrace is to generate error in constructor and save it's stack. It would give proper call stack + 1 line for constructor (it's a suitable pay-off): this.stack = new Error().stack;Tasty
Creating a custom error is not very useful if it doesn't capture the stack. Use Error.captureStackTrace(this, this.constructor) in the constructor. This might be V8 only.Festus
Assigning the prototype kills performance. The numbers are shown at windward.net/blogs/… - please consider a different approach as people will use the above as the selected and top voted answer.Airtoair
@DavidThielen where is Kevin assigning the prototype, except the one time when creating the type? I don't see how your comment is relevant here.Rebeca
Why not better to do Child.prototype = Object.create( Parent.prototype ) ?Nodus
-1; this is wrong. Doing NotImplementedError.prototype = Error.prototype; doesn't make instanceof treat NotImplementedError as a subclass of Error, it makes instanceof treat them as the exact same class. If you paste the above code into your console and try new Error() instanceof NotImplementedError you will get true, which is clearly wrong.Rosewood
comments are tl;dr, but downvote bcouse no stacktraceSunburst
I wanted to just throw an object too but apparently I cannot handle responses in GraphQL. For some reasons if statements don't word there. I would appreciate is any of you share a good practice of how it should work and be more comforable to sustain. That's why now I'm thinking about throwing ErrorsFulminant
B
131

In ES2015, you can use class to do this cleanly:

class NotImplemented extends Error {
  constructor(message = "", ...args) {
    super(message, ...args);
    this.message = message + " has not yet been implemented.";
  }
}

This does not modify the global Error prototype, allows you to customize message, name, and other attributes, and properly captures the stack. It's also pretty readable.

Of course, you may need to use a tool like babel if your code will be running on older browsers.

Beniamino answered 14/6, 2017 at 16:9 Comment(3)
Be aware if you use babel it has limitation on not being able to extend built in Error class: babeljs.io/docs/en/caveats/#classesIncest
For more details on extending errors, check out Custom Errors here developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/…Hasseman
The main problem with this is that in the console it says "Uncaught Error" instead of "Uncaught NotImplemented". To solve this, you need to add NotImplemented.prototype.name = 'NotImplemented';.Aminopyrine
N
94

All of the above answers are terrible awful - really. Even the one with 107 ups! The real answer is here guys:

Inheriting from the Error object - where is the message property?

TL;DR:

A. The reason message isn't being set is that Error is a function that returns a new Error object and does not manipulate this in any way.

B. The way to do this right is to return the result of the apply from the constructor, as well as setting the prototype in the usual complicated javascripty way:

function MyError() {
    var temp = Error.apply(this, arguments);
    temp.name = this.name = 'MyError';
    this.message = temp.message;
    if(Object.defineProperty) {
        // getter for more optimizy goodness
        /*this.stack = */Object.defineProperty(this, 'stack', { 
            get: function() {
                return temp.stack
            },
            configurable: true // so you can change it if you want
        })
    } else {
        this.stack = temp.stack
    }
}
//inherit prototype using ECMAScript 5 (IE 9+)
MyError.prototype = Object.create(Error.prototype, {
    constructor: {
        value: MyError,
        writable: true,
        configurable: true
    }
});

var myError = new MyError("message");
console.log("The message is: '" + myError.message + "'"); // The message is: 'message'
console.log(myError instanceof Error); // true
console.log(myError instanceof MyError); // true
console.log(myError.toString()); // MyError: message
console.log(myError.stack); // MyError: message \n 
// <stack trace ...>


 
//for EMCAScript 4 or ealier (IE 8 or ealier), inherit prototype this way instead of above code:
/*
var IntermediateInheritor = function() {};
IntermediateInheritor.prototype = Error.prototype;
MyError.prototype = new IntermediateInheritor();
*/

You could probably do some trickery to enumerate through all the non-enumerable properties of the tmp Error to set them rather than explicitly setting only stack and message, but the trickery isn't supported in ie<9

Never answered 26/7, 2013 at 21:12 Comment(4)
This solution also works for instantiating a custom error with an existing error. If you're using a third party library and want to wrap an existing error with your own custom type, the other methods do not work properly. FYI, you can instantiate vanilla Errors by passing them an existing error.Chadwick
I simplified and improved this approach a bit: jsbin.com/rolojuhuya/1/edit?js,consoleZweig
@MattKantor: I prefer Error.apply(this, arguments) but I too think your code is better.Devindevina
Instead of temp.name = this.name = 'MyError', you can do temp.name = this.name = this.constructor.name. That way it will work for subclasses of MyError as well.Polycotyledon
F
29

If anyone is curious on how to create a custom error and get the stack trace:

function CustomError(message) {
  this.name = 'CustomError';
  this.message = message || '';
  var error = new Error(this.message);
  error.name = this.name;
  this.stack = error.stack;
}
CustomError.prototype = Object.create(Error.prototype);

try {
  throw new CustomError('foobar');
}
catch (e) {
  console.log('name:', e.name);
  console.log('message:', e.message);
  console.log('stack:', e.stack);
}
Fiesta answered 22/12, 2014 at 2:12 Comment(0)
S
11
class NotImplementedError extends Error {
  constructor(message) {
    super(message);
    this.message = message;
  }
}
NotImplementedError.prototype.name = 'NotImplementedError';
module.exports = NotImplementedError;

and

try {
  var e = new NotImplementedError("NotImplementedError message");
  throw e;
} catch (ex1) {
  console.log(ex1.stack);
  console.log("ex1 instanceof NotImplementedError = " + (ex1 instanceof NotImplementedError));
  console.log("ex1 instanceof Error = " + (ex1 instanceof Error));
  console.log("ex1.name = " + ex1.name);
  console.log("ex1.message = " + ex1.message);
}

It is just a class representation of this answer.

output

NotImplementedError: NotImplementedError message
  ...stacktrace
ex1 instanceof NotImplementedError = true
ex1 instanceof Error = true
ex1.name = NotImplementedError
ex1.message = NotImplementedError message
Seamanlike answered 10/8, 2020 at 8:57 Comment(0)
K
9

I like to do it like this:

  • Make use of name so toString() throws "{code}: {message}"
  • Attach code to error.code as checking/parsing a code is better in code than checking a message, which you might want to localize for example
  • Attach message to error.message as an alternative to error.toString()

class AppException extends Error {
  constructor(code, message) {
    const fullMsg = message ? `${code}: ${message}` : code;
    super(fullMsg);
    this.name = code;
    this.code = code;
    this.message = fullMsg;
  }
  
  toString() {
    return this.message;
  }
}

// Just a code
try {
  throw new AppException('FORBIDDEN');
} catch(e) {
  console.error(e);
  console.error(e.toString());
  console.log(e.code === 'FORBIDDEN');
}

// A code and a message
try {
  throw new AppException('FORBIDDEN', 'You don\'t have access to this page');
} catch(e) {
  console.error(e);
  console.error(e.toString());
  console.log(e.code === 'FORBIDDEN');
}
Kelda answered 21/9, 2018 at 23:42 Comment(0)
T
8

This section of the standard may explain why the Error.apply call doesn't initialize the object:

15.11.1 The Error Constructor Called as a Function

When Error is called as a function rather than as a constructor, it creates and initialises a new Error object. Thus the function call Error(...) is equivalent to the object creation expression new Error(...) with the same arguments.

In this case the Error function probably determines that it's not being called as a constructor, so it returns a new Error instance rather than initializing the this object.

Testing with the following code seems to demonstrate that this is in fact what's happening:

function NotImplementedError() { 
   var returned = Error.apply(this, arguments);
   console.log("returned.message = '" + returned.message + "'");
   console.log("this.message = '" + this.message + "'");
}
NotImplementedError.prototype = new Error();

var nie = new NotImplementedError("some message");

The following output is generated when this is run:

returned.message = 'some message'
this.message = ''
Tourbillion answered 12/8, 2011 at 6:31 Comment(9)
how could this be simulated with a custom error class? For example, how could my custom error class be used as both a function that creates an instance and as a constructor?Plemmons
No, this is not true. If it returned a new Error instance, then his msg property would work.Never
@BT How does the msg property on the new instance affect the msg property on this in Error.apply(this, arguments);? I'm saying the call to Error here is constructing a new object, which is thrown away; not initializing the already constructed object which is assigned to nie.Tourbillion
@BT I've added some example code that hopefully makes clearer what I was trying to say.Tourbillion
@Tourbillion I may have misunderstood the purpose here, but shouldn't your NotImplementedError implementation return the returned variable?Outsider
@b.long With my code sample I was trying to demonstrate why the original code didn't work. The Error.apply call returns a new object instead of updating this.Tourbillion
Returning returned from the constructor wouldn't work, because then new NotImplementedError(...) would return an object that is not an instance of NotImplementedError.Tourbillion
Thanks for elaborating @Dave, I understand now. A quick follow-up question, would you recommend the solution posted by Kevin Hakanson , specifically his NotImplementedError2 implementation?Outsider
@b.long The issue with the NotImplementedError2 solution is that you end up with a stacktrace from where the Error instance was created for the prototype, rather than from the site of the throw. If that's not an issue for you then it would be a fine choice.Tourbillion
O
7
function InvalidValueError(value, type) {
    this.message = "Expected `" + type.name + "`: " + value;
    var error = new Error(this.message);
    this.stack = error.stack;
}
InvalidValueError.prototype = new Error();
InvalidValueError.prototype.name = InvalidValueError.name;
InvalidValueError.prototype.constructor = InvalidValueError;
Overcome answered 20/11, 2013 at 5:43 Comment(1)
This is the best answer here. It is succint and the exception created this way will behave correctly in all situations. It also preserves stack trace which is very important in non trivial applications. I would only replace "prototype = new Error()" with "prototype = Object.create(Error.prototype)". For Node.js there is a small library that does this for you: npmjs.com/package/node-custom-errorsRefractor
A
7

Accoring to Joyent you shouldn’t mess with the stack property (which I see in lots of answers given here), because it will have a negative impact on performance. Here is what they say:

stack: generally, don't mess with this. Don't even augment it. V8 only computes it if someone actually reads the property, which improves performance dramatically for handlable errors. If you read the property just to augment it, you'll end up paying the cost even if your caller doesn't need the stack.

I like and would like to mention their idea of wrapping the original error which is a nice replacement for passing on the stack.

So here is how I create a custom error, considering the above mentioned:

es5 version:

function RError(options) {
    options = options || {}; // eslint-disable-line no-param-reassign
    this.name = options.name;
    this.message = options.message;
    this.cause = options.cause;

    // capture stack (this property is supposed to be treated as private)
    this._err = new Error();

    // create an iterable chain
    this.chain = this.cause ? [this].concat(this.cause.chain) : [this];
}
RError.prototype = Object.create(Error.prototype, {
    constructor: {
        value: RError,
        writable: true,
        configurable: true
    }
});

Object.defineProperty(RError.prototype, 'stack', {
    get: function stack() {
        return this.name + ': ' + this.message + '\n' + this._err.stack.split('\n').slice(2).join('\n');
    }
});

Object.defineProperty(RError.prototype, 'why', {
    get: function why() {
        var _why = this.name + ': ' + this.message;
        for (var i = 1; i < this.chain.length; i++) {
            var e = this.chain[i];
            _why += ' <- ' + e.name + ': ' + e.message;
        }
        return _why;
    }
});

// usage

function fail() {
    throw new RError({
        name: 'BAR',
        message: 'I messed up.'
    });
}

function failFurther() {
    try {
        fail();
    } catch (err) {
        throw new RError({
            name: 'FOO',
            message: 'Something went wrong.',
            cause: err
        });
    }
}

try {
    failFurther();
} catch (err) {
    console.error(err.why);
    console.error(err.stack);
    console.error(err.cause.stack);
}

es6 version:

class RError extends Error {
    constructor({name, message, cause}) {
        super();
        this.name = name;
        this.message = message;
        this.cause = cause;
    }
    [Symbol.iterator]() {
        let current = this;
        let done = false;
        const iterator = {
            next() {
                const val = current;
                if (done) {
                    return { value: val, done: true };
                }
                current = current.cause;
                if (!val.cause) {
                    done = true;
                }
                return { value: val, done: false };
            }
        };
        return iterator;
    }
    get why() {
        let _why = '';
        for (const e of this) {
            _why += `${_why.length ? ' <- ' : ''}${e.name}: ${e.message}`;
        }
        return _why;
    }
}

// usage

function fail() {
    throw new RError({
        name: 'BAR',
        message: 'I messed up.'
    });
}

function failFurther() {
    try {
        fail();
    } catch (err) {
        throw new RError({
            name: 'FOO',
            message: 'Something went wrong.',
            cause: err
        });
    }
}

try {
    failFurther();
} catch (err) {
    console.error(err.why);
    console.error(err.stack);
    console.error(err.cause.stack);
}

I’ve put my solution into a module, here it is: https://www.npmjs.com/package/rerror

Antimony answered 19/10, 2016 at 9:48 Comment(0)
C
6

I had a similar issue to this. My error needs to be an instanceof both Error and NotImplemented, and it also needs to produce a coherent backtrace in the console.

My solution:

var NotImplemented = (function() {
  var NotImplemented, err;
  NotImplemented = (function() {
    function NotImplemented(message) {
      var err;
      err = new Error(message);
      err.name = "NotImplemented";
      this.message = err.message;
      if (err.stack) this.stack = err.stack;
    }
    return NotImplemented;
  })();
  err = new Error();
  err.name = "NotImplemented";
  NotImplemented.prototype = err;

  return NotImplemented;
}).call(this);

// TEST:
console.log("instanceof Error: " + (new NotImplemented() instanceof Error));
console.log("instanceof NotImplemented: " + (new NotImplemented() instanceofNotImplemented));
console.log("message: "+(new NotImplemented('I was too busy').message));
throw new NotImplemented("just didn't feel like it");

Result of running with node.js:

instanceof Error: true
instanceof NotImplemented: true
message: I was too busy

/private/tmp/t.js:24
throw new NotImplemented("just didn't feel like it");
      ^
NotImplemented: just didn't feel like it
    at Error.NotImplemented (/Users/colin/projects/gems/jax/t.js:6:13)
    at Object.<anonymous> (/Users/colin/projects/gems/jax/t.js:24:7)
    at Module._compile (module.js:449:26)
    at Object.Module._extensions..js (module.js:467:10)
    at Module.load (module.js:356:32)
    at Function.Module._load (module.js:312:12)
    at Module.runMain (module.js:487:10)
    at process.startup.processNextTick.process._tickCallback (node.js:244:9)

The error passes all 3 of my criteria, and although the stack property is nonstandard, it is supported in most newer browsers which is acceptable in my case.

Carditis answered 16/5, 2012 at 11:56 Comment(0)
S
3

I used the Constructor Pattern to create the new error object. I defined the prototype chain such as an Error instance. See the MDN Error constructor reference.

You can check this snippet on this gist.

IMPLEMENTATION

// Creates user-defined exceptions
var CustomError = (function() {
  'use strict';

  //constructor
  function CustomError() {
    //enforces 'new' instance
    if (!(this instanceof CustomError)) {
      return new CustomError(arguments);
    }
    var error,
      //handles the arguments object when is passed by enforcing a 'new' instance
      args = Array.apply(null, typeof arguments[0] === 'object' ? arguments[0] : arguments),
      message = args.shift() || 'An exception has occurred';

    //builds the message with multiple arguments
    if (~message.indexOf('}')) {
      args.forEach(function(arg, i) {
        message = message.replace(RegExp('\\{' + i + '}', 'g'), arg);
      });
    }

    //gets the exception stack
    error = new Error(message);
    //access to CustomError.prototype.name
    error.name = this.name;

    //set the properties of the instance
    //in order to resemble an Error instance
    Object.defineProperties(this, {
      stack: {
        enumerable: false,
        get: function() { return error.stack; }
      },
      message: {
        enumerable: false,
        value: message
      }
    });
  }

  // Creates the prototype and prevents the direct reference to Error.prototype;
  // Not used new Error() here because an exception would be raised here,
  // but we need to raise the exception when CustomError instance is created.
  CustomError.prototype = Object.create(Error.prototype, {
    //fixes the link to the constructor (ES5)
    constructor: setDescriptor(CustomError),
    name: setDescriptor('JSU Error')
  });

  function setDescriptor(value) {
    return {
      configurable: false,
      enumerable: false,
      writable: false,
      value: value
    };
  }

  //returns the constructor
  return CustomError;
}());

USAGE

The CustomError constructor can receive many arguments to build the message, e.g.

var err1 = new CustomError("The url of file is required"),
    err2 = new CustomError("Invalid Date: {0}", +"date"),
    err3 = new CustomError("The length must be greater than {0}", 4),
    err4 = new CustomError("Properties .{0} and .{1} don't exist", "p1", "p2");

throw err4;

And this is how the custom error looks:

Custom error prototype chain

Saint answered 16/2, 2015 at 17:33 Comment(0)
C
3

This is my implementation:

class HttpError extends Error {
  constructor(message, code = null, status = null, stack = null, name = null) {
    super();
    this.message = message;
    this.status = 500;

    this.name = name || this.constructor.name;
    this.code = code || `E_${this.name.toUpperCase()}`;
    this.stack = stack || null;
  }

  static fromObject(error) {
    if (error instanceof HttpError) {
      return error;
    }
    else {
      const { message, code, status, stack } = error;
      return new ServerError(message, code, status, stack, error.constructor.name);
    }
  }

  expose() {
    if (this instanceof ClientError) {
      return { ...this };
    }
    else {
      return {
        name: this.name,
        code: this.code,
        status: this.status,
      }
    }
  }
}

class ServerError extends HttpError {}

class ClientError extends HttpError { }

class IncorrectCredentials extends ClientError {
  constructor(...args) {
    super(...args);
    this.status = 400;
  }
}

class ResourceNotFound extends ClientError {
  constructor(...args) {
    super(...args);
    this.status = 404;
  }
}

Example usage #1:

app.use((req, res, next) => {
  try {
    invalidFunction();
  }
  catch (err) {
    const error = HttpError.fromObject(err);
    return res.status(error.status).send(error.expose());
  }
});

Example usage #2:

router.post('/api/auth', async (req, res) => {
  try {
    const isLogged = await User.logIn(req.body.username, req.body.password);

    if (!isLogged) {
      throw new IncorrectCredentials('Incorrect username or password');
    }
    else {
      return res.status(200).send({
        token,
      });
    }
  }
  catch (err) {
    const error = HttpError.fromObject(err);
    return res.status(error.status).send(error.expose());
  }
});
Caravel answered 12/9, 2018 at 14:56 Comment(0)
B
2

I just had to implement something like this and found that the stack was lost in my own error implementation. What I had to do was create a dummy error and retrieve the stack from that:

My.Error = function (message, innerException) {
    var err = new Error();
    this.stack = err.stack; // IMPORTANT!
    this.name = "Error";
    this.message = message;
    this.innerException = innerException;
}
My.Error.prototype = new Error();
My.Error.prototype.constructor = My.Error;
My.Error.prototype.toString = function (includeStackTrace) {
    var msg = this.message;
    var e = this.innerException;
    while (e) {
        msg += " The details are:\n" + e.message;
        e = e.innerException;
    }
    if (includeStackTrace) {
        msg += "\n\nStack Trace:\n\n" + this.stack;
    }
    return msg;
}
Blades answered 31/5, 2012 at 11:14 Comment(1)
This doesn't set the messageNever
C
2

This is implemented nicely in the Cesium DeveloperError:

In it's simplified form:

var NotImplementedError = function(message) {
    this.name = 'NotImplementedError';
    this.message = message;
    this.stack = (new Error()).stack;
}

// Later on...

throw new NotImplementedError();
Chuppah answered 27/1, 2014 at 1:34 Comment(2)
This works great, except that the stack will contain an extra line for the error constructor, which can be a problem.Zinfandel
Also, does not pass the error instanceof Error test, which can be helpful.Nkrumah
F
1

The constructor needs to be like a factory method and return what you want. If you need additional methods/properties, you can add them to the object before returning it.

function NotImplementedError(message) { return new Error("Not implemented", message); }

x = new NotImplementedError();

Though I'm not sure why you'd need to do this. Why not just use new Error... ? Custom exceptions don't really add much in JavaScript (or probably any untyped language).

Froude answered 23/4, 2009 at 22:42 Comment(1)
You have to switch on Error-type-hierarchy or object-value in JavaScript because you can only specify a single catch block. In your solution, (x instanceof NotImplementedError) is false, which isn't acceptable in my case.Azaleeazan
D
0

At the expense of not being able to use instanceof, the following preserves the original stack trace and doesn't use any non-standard tricks.

// the function itself
var fixError = function(err, name) {
    err.name = name;
    return err;
}

// using the function
try {
    throw fixError(new Error('custom error message'), 'CustomError');
} catch (e) {
    if (e.name == 'CustomError')
        console.log('Wee! Custom Error! Msg:', e.message);
    else
        throw e; // unhandled. let it propagate upwards the call stack
}
Dodds answered 28/4, 2013 at 14:58 Comment(3)
all you gotta do here to be able to use instanceof is throw new fixError instead of just fixErrorNever
@BT: Not with the fixError function above. Adding a new when calling it would just create an object that gets thrown away.Darnel
Oh i guess i meant using "instanceof fixError" - of course then "instanceof Error" wouldn't work.. i guess that's worse..Never
L
0

Another alternative , might not work in all enviroments.Atleast assured it works in nodejs 0.8 This approach uses a non standard way of modifying the internal proto prop

function myError(msg){ 
      var e = new Error(msg); 
      _this = this; 
      _this.__proto__.__proto__ = e;
}
Luddite answered 30/7, 2013 at 9:0 Comment(0)
C
0

If you are using Node/Chrome. The following snippet will get you extension which meets the following requirements.

  • err instanceof Error
  • err instanceof CustomErrorType
  • console.log() returns [CustomErrorType] when created with a message
  • console.log() returns [CustomErrorType: message] when created without a message
  • throw/stack provides the information at the point the error was created.
  • Works optimally in Node.JS, and Chrome.
  • Will pass instanceof checks in Chrome, Safari, Firefox and IE 8+, but will not have a valid stack outside of Chrome/Safari. I'm OK with that because I can debug in chrome, but code which requires specific error types will still function cross browser. If you need Node only you can easily remove the if statements and you're good to go.

Snippet

var CustomErrorType = function(message) {
    if (Object.defineProperty) {
        Object.defineProperty(this, "message", {
            value : message || "",
            enumerable : false
        });
    } else {
        this.message = message;
    }

    if (Error.captureStackTrace) {
        Error.captureStackTrace(this, CustomErrorType);
    }
}

CustomErrorType.prototype = new Error();
CustomErrorType.prototype.name = "CustomErrorType";

Usage

var err = new CustomErrorType("foo");

Output

var err = new CustomErrorType("foo");
console.log(err);
console.log(err.stack);

[CustomErrorType: foo]
CustomErrorType: foo
    at Object.<anonymous> (/errorTest.js:27:12)
    at Module._compile (module.js:456:26)
    at Object.Module._extensions..js (module.js:474:10)
    at Module.load (module.js:356:32)
    at Function.Module._load (module.js:312:12)
    at Function.Module.runMain (module.js:497:10)
    at startup (node.js:119:16)
    at node.js:906:3

/errorTest.js:30
        throw err;
              ^
CustomErrorType: foo
    at Object.<anonymous> (/errorTest.js:27:12)
    at Module._compile (module.js:456:26)
    at Object.Module._extensions..js (module.js:474:10)
    at Module.load (module.js:356:32)
    at Function.Module._load (module.js:312:12)
    at Function.Module.runMain (module.js:497:10)
    at startup (node.js:119:16)
    at node.js:906:3
Crouch answered 24/10, 2014 at 20:31 Comment(0)
T
0

The following worked for me taken from the official Mozilla documentation Error.

function NotImplementedError(message) {
    var instance = new Error(message);
    instance.name = 'NotImplementedError';

    Object.setPrototypeOf(instance, Object.getPrototypeOf(this));
    if (Error.captureStackTrace) {
        Error.captureStackTrace(instance, NotImplementedError);
    }
    return instance;
}

NotImplementedError.prototype = Object.create(Error.prototype, {
    constructor: {
        value: Error,
        enumerable: false,
        writable: true,
        configurable: true
    }
});
Tindal answered 6/1, 2020 at 15:21 Comment(0)
L
0

Here is my solution for supporting pre-es2015 browsers. It does not do any fancy prototype tweaking and will not break debuggers.

/**  Custom Errors
    // Depends on underscore js
    // This will declare an CustError() class in both 'this' and '_exports' namespaces
    // ctor is optional
    declare_cust_error(function CustError(){}, {ns: [this, _exports], ctor: 
        function cust_err_ctor(instance, clazz, name, msg, info){
            q$.called(arguments)
        }
    })

    // Usage:
    // Second param (pojso) is optional
    try {
        throw CustError.create("foo", {k1: 'v1', k2: 'v2'})
    }catch(ex){
        if(CustError.is_inst(ex)){
            console.error("its a CustError", ex)
        } else {
            throw ex
        }
    }

**/
function declare_cust_error(error_class, opts){
    var p, c, cp
    if(!error_class||!(p=error_class.prototype))throw new Error("error_class must be a Class")
    try{
        c = p.constructor; cp = c.toString()
    }catch(ex){}
    if(!cp || cp.indexOf('function ') != 0 || cp.indexOf('[native code]') > 0)
        throw new Error("error_class must be a classic proto class (pre-es6) but got: " + error_class.toString())

    opts=opts||{}
    
    error_class.__is_cust_error__ = true
    error_class.__cust_error_name__ = c.name

    error_class.create = function cust_error_create(msg, info){
        var instance = new Error(msg)
        instance.info = info
        instance.__is_cust_error__ = true
        instance.__cust_error_name__ = c.name
        if(_.isFunction(opts.ctor)){
            opts.ctor(instance, error_class, c.name, msg, info)
        }
        return instance
    }

    error_class.is_inst = function cust_error_is_inst(instanace){
        return ( (instanace instanceof Error) && instanace.__cust_error_name__ === error_class.__cust_error_name__ )
    }
    
    // Declare error in namespace(s)
    _.each(_.isArray(opts.ns)?opts.ns:[opts.ns], function(ns){ ns[c.name] = error_class })

    return error_class

}
Leviticus answered 24/10, 2022 at 16:55 Comment(0)
D
0

A lot of the methods above won't work.

Errors

The last one is an actual error. If you use a string, it looks good, but it doesn't give a stack trace. If you throw with Error, you can't have "Uncaught BadError: bad", so you'll have to remove the custom error (sadly). If you throw an object, it looks kind of off, and the final one is just an average error.

This method creates an error with a custom name while preserving stack tracing:

var errProto = Object.create(Error.prototype, {
  constructor: {
    value: Error,
    enumerable: false,
    writable: true,
    configurable: true
  }
})
var isFirefox = !!window.InstallTrigger
// Hide stack for Firefox only, as stacks can cause problems with high "frame" counts.
function createError(name, message, hideStack) {
  if (message == null) {
    message = ""
  }
  var customError = Error(message)
  customError.name = name
  Object.setPrototypeOf(customError, errProto)
  if (isFirefox && hideStack) {
    customError.stack = ""
  } else if (isFirefox) {
    var stack = customError.stack
    var newline = stack.indexOf("\n") + 1
    stack = stack.slice(newline)
    customError.stack = stack
    var split = stack.split(":")
    if (split.length > 4) {
      var a = split[3]
      var b = split[4]
      var t = b.slice(0, b.indexOf("\n"))
      customError.lineNumber = Number(a)
      customError.columnNumber = Number(t)
    }
  } else {
    var stack = customError.stack
    var split = stack.split("\n")
    var secondPart = split.slice(2).join("\n")
    stack = split[0] + "\n" + secondPart
    customError.stack = stack
    var split = secondPart.split(":")
    var a = split[2]
    var b = split[3]
  }
  throw customError
}

var frame = 0

function aFunction() {
  if (++frame === 100) {
    createError("LazyError", "function getting lazy", false, true)
  } else {
    requestAnimationFrame(aFunction)
  }
}

setTimeout(aFunction, Math.random() * 500)
* {
  font-family: Verdana;
}
Check your inspector!
Delao answered 17/12, 2022 at 17:15 Comment(0)
W
-1

Try a new prototype object for each instance of the user defined error type. It allows instanceof checks to behave as usual plus type and message are correctly reported in Firefox and V8 (Chome, nodejs).

function NotImplementedError(message){
    if(NotImplementedError.innercall===undefined){
        NotImplementedError.innercall = true;
        NotImplementedError.prototype = new Error(message);
        NotImplementedError.prototype.name = "NotImplementedError";
        NotImplementedError.prototype.constructor = NotImplementedError;

        return new NotImplementedError(message);
    }
    delete NotImplementedError.innercall;
}

Note that an additional entry will preceed the otherwise correct stack.

Westernmost answered 19/8, 2012 at 21:9 Comment(1)
Doesn't work. Try: var a = new NotImplementedError('a'), b = new NotImplementedError('b');. Now a instanceof NotImplementedError == false and b instanceof NotImplementedError == trueDetestation
H
-2

This is fastest way to do it:

    let thisVar = false

    if (thisVar === false) {
            throw new Error("thisVar is false. It should be true.")
    }
Humfried answered 5/2, 2020 at 17:19 Comment(0)
S
-3

easier way. You could make your object inherit from the Error object. Example:

function NotImplementError(message)
{
    this.message = message;
    Error.call();
    Error.call(message);
} 

what we are doing is using the function call() which call the constructor of the Error class so is basicly the same thing as implementing a class inheritance in other object oriented languages.

Straightlaced answered 6/3, 2013 at 19:27 Comment(0)
I
-3

MDN has an excellent example:

try {
  throw new Error('Whoops!');
} catch (e) {
  console.log(e.name + ': ' + e.message);
}
Ichnology answered 4/9, 2017 at 21:59 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.