I want to throw some things in my JS code and I want them to be instanceof Error, but I also want to have them be something else.
In Python, typically, one would subclass Exception.
What\'s the appropriate thing to do in JS?
I want to throw some things in my JS code and I want them to be instanceof Error, but I also want to have them be something else.
In Python, typically, one would subclass Exception.
What\'s the appropriate thing to do in JS?
The only standard field Error object has is the message
property. (See MDN, or EcmaScript Language Specification, section 15.11) Everything else is platform specific.
Mosts environments set the stack
property, but fileName
and lineNumber
are practically useless to be used in inheritance.
So, the minimalistic approach is:
function MyError(message) {
this.name = \'MyError\';
this.message = message;
this.stack = (new Error()).stack;
}
MyError.prototype = new Error; // <-- remove this if you do not
// want MyError to be instanceof Error
You could sniff the stack, unshift unwanted elements from it and extract information like fileName and lineNumber, but doing so requires information about the platform JavaScript is currently running upon. Most cases that is unnecessary -- and you can do it in post-mortem if you really want.
Safari is a notable exception. There is no stack
property, but the throw
keyword sets sourceURL
and line
properties of the object that is being thrown. Those things are guaranteed to be correct.
Test cases I used can be found here: JavaScript self-made Error object comparison.
In ES6:
class MyError extends Error {
constructor(message) {
super(message);
this.name = \'MyError\';
}
}
source
Edit: Please read comments. It turns out this only works well in V8 (Chrome / Node.JS) My intent was to provide a cross-browser solution, which would work in all browsers, and provide stack trace where support is there.
Edit: I made this Community Wiki to allow for more editing.
Solution for V8 (Chrome / Node.JS), works in Firefox, and can be modified to function mostly correctly in IE. (see end of post)
function UserError(message) {
this.constructor.prototype.__proto__ = Error.prototype // Make this an instanceof Error.
Error.call(this) // Does not seem necessary. Perhaps remove this line?
Error.captureStackTrace(this, this.constructor) // Creates the this.stack getter
this.name = this.constructor.name; // Used to cause messages like \"UserError: message\" instead of the default \"Error: message\"
this.message = message; // Used to set the message
}
Original post on \"Show me the code !\"
Short version:
function UserError(message) {
this.constructor.prototype.__proto__ = Error.prototype
Error.captureStackTrace(this, this.constructor)
this.name = this.constructor.name
this.message = message
}
I keep this.constructor.prototype.__proto__ = Error.prototype
inside the function to keep all the code together. But you can also replace this.constructor
with UserError
and that allows you to move the code to outside the function, so it only gets called once.
If you go that route, make sure you call that line before the first time you throw UserError
.
That caveat does not apply the function, because functions are created first, no matter the order. Thus, you can move the function to the end of the file, without a problem.
Browser Compatibility
Works in Firefox and Chrome (and Node.JS) and fills all promises.
Internet Explorer fails in the following
Errors do not have err.stack
to begin with, so \"it\'s not my fault\".
Error.captureStackTrace(this, this.constructor)
does not exist so you need to do something else like
if(Error.captureStackTrace) // AKA if not IE
Error.captureStackTrace(this, this.constructor)
toString
ceases to exist when you subclass Error
. So you also need to add.
else
this.toString = function () { return this.name + \': \' + this.message }
IE will not consider UserError
to be an instanceof Error
unless you run the following some time before you throw UserError
UserError.prototype = Error.prototype
In short:
If you are using ES6 without transpilers:
class CustomError extends Error { /* ... */}
If you are using Babel transpiler:
Option 1: use babel-plugin-transform-builtin-extend
Option 2: do it yourself (inspired from that same library)
function CustomError(...args) {
const instance = Reflect.construct(Error, args);
Reflect.setPrototypeOf(instance, Reflect.getPrototypeOf(this));
return instance;
}
CustomError.prototype = Object.create(Error.prototype, {
constructor: {
value: Error,
enumerable: false,
writable: true,
configurable: true
}
});
Reflect.setPrototypeOf(CustomError, Error);
If you are using pure ES5:
function CustomError(message, fileName, lineNumber) {
var instance = new Error(message, fileName, lineNumber);
Object.setPrototypeOf(instance, Object.getPrototypeOf(this));
return instance;
}
CustomError.prototype = Object.create(Error.prototype, {
constructor: {
value: Error,
enumerable: false,
writable: true,
configurable: true
}
});
if (Object.setPrototypeOf){
Object.setPrototypeOf(CustomError, Error);
} else {
CustomError.__proto__ = Error;
}
Alternative: use Classtrophobic framework
Explanation:
Why extending the Error class using ES6 and Babel is a problem?
Because an instance of CustomError is not anymore recognized as such.
class CustomError extends Error {}
console.log(new CustomError(\'test\') instanceof Error);// true
console.log(new CustomError(\'test\') instanceof CustomError);// false
In fact, from the official documentation of Babel, you cannot extend any built-in JavaScript classes such as Date
, Array
, DOM
or Error
.
The issue is described here:
What about the other SO answers?
All the given answers fix the instanceof
issue but you lose the regular error console.log
:
console.log(new CustomError(\'test\'));
// output:
// CustomError {name: \"MyError\", message: \"test\", stack: \"Error↵ at CustomError (<anonymous>:4:19)↵ at <anonymous>:1:5\"}
Whereas using the method mentioned above, not only you fix the instanceof
issue but you also keep the regular error console.log
:
console.log(new CustomError(\'test\'));
// output:
// Error: test
// at CustomError (<anonymous>:2:32)
// at <anonymous>:1:5
To avoid the boilerplate for every different type of error, I combined the wisdom of some of the solutions into a createErrorType
function:
function createErrorType(name, init) {
function E(message) {
if (!Error.captureStackTrace)
this.stack = (new Error()).stack;
else
Error.captureStackTrace(this, this.constructor);
this.message = message;
init && init.apply(this, arguments);
}
E.prototype = new Error();
E.prototype.name = name;
E.prototype.constructor = E;
return E;
}
Then you can define new error types easily as follows:
var NameError = createErrorType(\'NameError\', function (name, invalidChar) {
this.message = \'The name \' + name + \' may not contain \' + invalidChar;
});
var UnboundError = createErrorType(\'UnboundError\', function (variableName) {
this.message = \'Variable \' + variableName + \' is not bound\';
});
In 2018, I think this is the best way; that supports IE9+ and modern browsers.
UPDATE: See this test and repo for comparison on different implementations.
function CustomError(message) {
Object.defineProperty(this, \'name\', {
enumerable: false,
writable: false,
value: \'CustomError\'
});
Object.defineProperty(this, \'message\', {
enumerable: false,
writable: true,
value: message
});
if (Error.hasOwnProperty(\'captureStackTrace\')) { // V8
Error.captureStackTrace(this, CustomError);
} else {
Object.defineProperty(this, \'stack\', {
enumerable: false,
writable: false,
value: (new Error(message)).stack
});
}
}
if (typeof Object.setPrototypeOf === \'function\') {
Object.setPrototypeOf(CustomError.prototype, Error.prototype);
} else {
CustomError.prototype = Object.create(Error.prototype, {
constructor: { value: CustomError }
});
}
Also beware that __proto__
property is deprecated which is widely used in other answers.
Crescent Fresh\'s answer highly-voted answer is misleading. Though his warnings are invalid, there are other limitations that he doesn\'t address.
First, the reasoning in Crescent\'s \"Caveats:\" paragraph doesn\'t make sense. The explanation implies that coding \"a bunch of if (error instanceof MyError) else ...\" is somehow burdensome or verbose compared to multiple catch statements. Multiple instanceof statements in a single catch block are just as concise as multiple catch statements-- clean and concise code without any tricks. This is a great way to emulate Java\'s great throwable-subtype-specific error handling.
WRT \"appears the message property of the subclass does not get set\", that is not the case if you use a properly constructed Error subclass. To make your own ErrorX Error subclass, just copy the code block beginning with \"var MyError =\", changing the one word \"MyError\" to \"ErrorX\". (If you want to add custom methods to your subclass, follow the sample text).
The real and significant limitation of JavaScript error subclassing is that for JavaScript implementations or debuggers that track and report on stack trace and location-of-instantiation, like FireFox, a location in your own Error subclass implementation will be recorded as the instantiation point of the class, whereas if you used a direct Error, it would be the location where you ran \"new Error(...)\"). IE users would probably never notice, but users of Fire Bug on FF will see useless file name and line number values reported alongside these Errors, and will have to drill down on the stack trace to element #1 to find the real instantiation location.
For the sake of completeness -- just because none of the previous answers mentioned this method -- if you are working with Node.js and don\'t have to care about browser compatibility, the desired effect is pretty easy to achieve with the built in inherits
of the util
module (official docs here).
For example, let\'s suppose you want to create a custom error class that takes an error code as the first argument and the error message as the second argument:
file custom-error.js:
\'use strict\';
var util = require(\'util\');
function CustomError(code, message) {
Error.captureStackTrace(this, CustomError);
this.name = CustomError.name;
this.code = code;
this.message = message;
}
util.inherits(CustomError, Error);
module.exports = CustomError;
Now you can instantiate and pass/throw your CustomError
:
var CustomError = require(\'./path/to/custom-error\');
// pass as the first argument to your callback
callback(new CustomError(404, \'Not found!\'));
// or, if you are working with try/catch, throw it
throw new CustomError(500, \'Server Error!\');
Note that, with this snippet, the stack trace will have the correct file name and line, and the error instance will have the correct name!
This happens due to the usage of the captureStackTrace
method, which creates a stack
property on the target object (in this case, the CustomError
being instantiated). For more details about how it works, check the documentation here.
How about this solution?
Instead of throwing your custom Error using:
throw new MyError(\"Oops!\");
You would wrap the Error object (kind of like a Decorator):
throw new MyError(Error(\"Oops!\"));
This makes sure all of the attributes are correct, such as the stack, fileName lineNumber, et cetera.
All you have to do then is either copy over the attributes, or define getters for them. Here is an example using getters (IE9):
function MyError(wrapped)
{
this.wrapped = wrapped;
this.wrapped.name = \'MyError\';
}
function wrap(attr)
{
Object.defineProperty(MyError.prototype, attr, {
get: function()
{
return this.wrapped[attr];
}
});
}
MyError.prototype = Object.create(Error.prototype);
MyError.prototype.constructor = MyError;
wrap(\'name\');
wrap(\'message\');
wrap(\'stack\');
wrap(\'fileName\');
wrap(\'lineNumber\');
wrap(\'columnNumber\');
MyError.prototype.toString = function()
{
return this.wrapped.toString();
};
My solution is more simple than the other answers provided and doesn\'t have the downsides.
It preserves the Error prototype chain and all properties on Error without needing specific knowledge of them. It\'s been tested in Chrome, Firefox, Node, and IE11.
The only limitation is an extra entry at the top of the call stack. But that is easily ignored.
Here\'s an example with two custom parameters:
function CustomError(message, param1, param2) {
var err = new Error(message);
Object.setPrototypeOf(err, CustomError.prototype);
err.param1 = param1;
err.param2 = param2;
return err;
}
CustomError.prototype = Object.create(
Error.prototype,
{name: {value: \'CustomError\', enumerable: false}}
);
Example Usage:
try {
throw new CustomError(\'Something Unexpected Happened!\', 1234, \'neat\');
} catch (ex) {
console.log(ex.name); //CustomError
console.log(ex.message); //Something Unexpected Happened!
console.log(ex.param1); //1234
console.log(ex.param2); //neat
console.log(ex.stack); //stacktrace
console.log(ex instanceof Error); //true
console.log(ex instanceof CustomError); //true
}
For environments that require a polyfil of setPrototypeOf:
Object.setPrototypeOf = Object.setPrototypeOf || function (obj, proto) {
obj.__proto__ = proto;
return obj;
};
In the above example Error.apply
(also Error.call
) doesn\'t do anything for me (Firefox 3.6/Chrome 5). A workaround I use is:
function MyError(message, fileName, lineNumber) {
var err = new Error();
if (err.stack) {
// remove one stack level:
if (typeof(Components) != \'undefined\') {
// Mozilla:
this.stack = err.stack.substring(err.stack.indexOf(\'\\n\')+1);
}
else if (typeof(chrome) != \'undefined\' || typeof(process) != \'undefined\') {
// Google Chrome/Node.js:
this.stack = err.stack.replace(/\\n[^\\n]*/,\'\');
}
else {
this.stack = err.stack;
}
}
this.message = message === undefined ? err.message : message;
this.fileName = fileName === undefined ? err.fileName : fileName;
this.lineNumber = lineNumber === undefined ? err.lineNumber : lineNumber;
}
MyError.prototype = new Error();
MyError.prototype.constructor = MyError;
MyError.prototype.name = \'MyError\';
As some people have said, it\'s fairly easy with ES6:
class CustomError extends Error { }
So I tried that within my app, (Angular, Typescript) and it just didn\'t work. After some time I\'ve found that the problem is coming from Typescript :O
See https://github.com/Microsoft/TypeScript/issues/13965
It\'s very disturbing because if you do:
class CustomError extends Error {}
try {
throw new CustomError()
} catch(e) {
if (e instanceof CustomError) {
console.log(\'Custom error\');
} else {
console.log(\'Basic error\');
}
}
In node or directly into your browser it\'ll display: Custom error
Try to run that with Typescript in your project on on Typescript playground, it\'ll display Basic error
...
The solution is to do the following:
class CustomError extends Error {
// we have to do the following because of: https://github.com/Microsoft/TypeScript/issues/13965
// otherwise we cannot use instanceof later to catch a given type
public __proto__: Error;
constructor(message?: string) {
const trueProto = new.target.prototype;
super(message);
this.__proto__ = trueProto;
}
}
I just want to add to what others have already stated:
To make sure that the custom error class shows up properly in the stack trace, you need to set the custom error class\'s prototype\'s name property to the custom error class\'s name property. This is what I mean:
CustomError.prototype = Error.prototype;
CustomError.prototype.name = \'CustomError\';
So the full example would be:
var CustomError = function(message) {
var err = new Error(message);
err.name = \'CustomError\';
this.name = err.name;
this.message = err.message;
//check if there is a stack property supported in browser
if (err.stack) {
this.stack = err.stack;
}
//we should define how our toString function works as this will be used internally
//by the browser\'s stack trace generation function
this.toString = function() {
return this.name + \': \' + this.message;
};
};
CustomError.prototype = new Error();
CustomError.prototype.name = \'CustomError\';
When all is said and done, you throw your new exception and it looks like this (I lazily tried this in the chrome dev tools):
CustomError: Stuff Happened. GASP!
at Error.CustomError (<anonymous>:3:19)
at <anonymous>:2:7
at Object.InjectedScript._evaluateOn (<anonymous>:603:39)
at Object.InjectedScript._evaluateAndWrap (<anonymous>:562:52)
at Object.InjectedScript.evaluate (<anonymous>:481:21)
My 2 cents:
a) Because accessing the Error.stack
property (as in some answers) have a large performance penalty.
b) Because it is only one line.
c) Because the solution at https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Error does not seems to preserve stack info.
//MyError class constructor
function MyError(msg){
this.__proto__.__proto__ = Error.apply(null, arguments);
};
usage example
http://jsfiddle.net/luciotato/xXyeB/
this.__proto__.__proto__
is MyError.prototype.__proto__
, so it is setting the __proto__
FOR ALL INSTANCES
of MyError to a specific newly created Error. It keeps MyError class properties and methods and also puts the new Error properties (including .stack) in the __proto__
chain.
You can not have more than one instance of MyError with useful stack info.
Do not use this solution if you do not fully understand what this.__proto__.__proto__=
does.
Since JavaScript Exceptions are difficult to sub-class, I don\'t sub-class. I just create a new Exception class and use an Error inside of it. I change the Error.name property so that it looks like my custom exception on the console:
var InvalidInputError = function(message) {
var error = new Error(message);
error.name = \'InvalidInputError\';
return error;
};
The above new exception can be thrown just like a regular Error and it will work as expected, for example:
throw new InvalidInputError(\"Input must be a string\");
// Output: Uncaught InvalidInputError: Input must be a string
Caveat: the stack trace is not perfect, as it will bring you to where the new Error is created and not where you throw. This is not a big deal on Chrome because it provides you with a full stack trace directly in the console. But it\'s more problematic on Firefox, for example.
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 tmp = Error.apply(this, arguments);
tmp.name = this.name = \'MyError\'
this.stack = tmp.stack
this.message = tmp.message
return this
}
var IntermediateInheritor = function() {}
IntermediateInheritor.prototype = Error.prototype;
MyError.prototype = new IntermediateInheritor()
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 ...>
The only problems with this way of doing it at this point (i\'ve iterated it a bit) are that
stack
and message
aren\'t included in MyError
and The first problem could be fixed by iterating through all the non-enumerable properties of error using the trick in this answer: Is it possible to get the non-enumerable inherited property names of an object?, but this isn\'t supported by ie<9. The second problem could be solved by tearing out that line in the stack trace, but I\'m not sure how to safely do that (maybe just removing the second line of e.stack.toString() ??).
As pointed out in Mohsen\'s answer, in ES6 it\'s possible to extend errors using classes. It\'s a lot easier and their behavior is more consistent with native errors...but unfortunately it\'s not a simple matter to use this in the browser if you need to support pre-ES6 browsers. See below for some notes on how that might be implemented, but in the meantime I suggest a relatively simple approach that incorporates some of the best suggestions from other answers:
function CustomError(message) {
//This is for future compatibility with the ES6 version, which
//would display a similar message if invoked without the
//`new` operator.
if (!(this instanceof CustomError)) {
throw new TypeError(\"Constructor \'CustomError\' cannot be invoked without \'new\'\");
}
this.message = message;
//Stack trace in V8
if (Error.captureStackTrace) {
Error.captureStackTrace(this, CustomError);
}
else this.stack = (new Error).stack;
}
CustomError.prototype = Object.create(Error.prototype);
CustomError.prototype.name = \'CustomError\';
In ES6 it\'s as simple as:
class CustomError extends Error {}
...and you can detect support for ES6 classes with try {eval(\'class X{}\')
, but you\'ll get a syntax error if you attempt to include the ES6 version in a script that\'s loaded by older browsers. So the only way to support all browsers would be to load a separate script dynamically (e.g. via AJAX or eval()
) for browsers that support ES6. A further complication is that eval()
isn\'t supported in all environments (due to Content Security Policies), which may or may not be a consideration for your project.
So for now, either the first approach above or simply using Error
directly without trying to extend it seems to be the best that can practically be done for code that needs to support non-ES6 browsers.
There is one other approach that some people might want to consider, which is to use Object.setPrototypeOf()
where available to create an error object that\'s an instance of your custom error type but which looks and behaves more like a native error in the console (thanks to Ben\'s answer for the recommendation). Here\'s my take on that approach: https://gist.github.com/mbrowne/fe45db61cea7858d11be933a998926a8. But given that one day we\'ll be able to just use ES6, personally I\'m not sure the complexity of that approach is worth it.
I would take a step back and consider why you want to do that? I think the point is to deal with different errors differently.
For example, in Python, you can restrict the catch statement to only catch MyValidationError
, and perhaps you want to be able to do something similar in javascript.
catch (MyValidationError e) {
....
}
You can\'t do this in javascript. There\'s only going to be one catch block. You\'re supposed to use an if statement on the error to determine its type.
catch(e) {
if(isMyValidationError(e)) {
...
} else {
// maybe rethrow?
throw e;
}
}
I think I would instead throw a raw object with a type, message, and any other properties you see fit.
throw { type: \"validation\", message: \"Invalid timestamp\" }
And when you catch the error:
catch(e) {
if(e.type === \"validation\") {
// handle error
}
// re-throw, or whatever else
}
This is based on George Bailey\'s answer, but extends and simplifies the original idea. It is written in CoffeeScript, but is easy to convert to JavaScript. The idea is extend Bailey\'s custom error with a decorator that wraps it, allowing you to create new custom errors easily.
Note: This will only work in V8. There is no support for Error.captureStackTrace
in other environments.
The decorator takes a name for the error type, and returns a function that takes an error message, and encloses the error name.
CoreError = (@message) ->
@constructor.prototype.__proto__ = Error.prototype
Error.captureStackTrace @, @constructor
@name = @constructor.name
BaseError = (type) ->
(message) -> new CoreError \"#{ type }Error: #{ message }\"
Now it is simple to create new error types.
StorageError = BaseError \"Storage\"
SignatureError = BaseError \"Signature\"
For fun, you could now define a function that throws a SignatureError
if it is called with too many args.
f = -> throw SignatureError \"too many args\" if arguments.length
This has been tested pretty well and seems to work perfectly on V8, maintaing the traceback, position etc.
Note: Using new
is optional when constructing a custom error.
The snippet shows it all.
function add(x, y) {
if (x && y) {
return x + y;
} else {
/**
*
* the error thrown will be instanceof Error class and InvalidArgsError also
*/
throw new InvalidArgsError();
// throw new Invalid_Args_Error();
}
}
// Declare custom error using using Class
class Invalid_Args_Error extends Error {
constructor() {
super(\"Invalid arguments\");
Error.captureStackTrace(this);
}
}
// Declare custom error using Function
function InvalidArgsError(message) {
this.message = `Invalid arguments`;
Error.captureStackTrace(this);
}
// does the same magic as extends keyword
Object.setPrototypeOf(InvalidArgsError.prototype, Error.prototype);
try{
add(2)
}catch(e){
// true
if(e instanceof Error){
console.log(e)
}
// true
if(e instanceof InvalidArgsError){
console.log(e)
}
}