316

In JS it doesn't seem possible to check if an argument passed to a function is actually of the type 'error' or an instance of Error.

For example, this is not valid:

typeof err === 'error'

since there are only 6 possible types (in the form of strings):

The typeof operator returns type information as a string. There are six possible values that typeof returns:

"number", "string", "boolean", "object", "function" and "undefined".

MSDN

But what if I have a simple use case like this:

function errorHandler(err) {

    if (typeof err === 'error') {
        throw err;
    }
    else {
        console.error('Unexpectedly, no error was passed to error handler. But here is the message:',err);
    }
}

so what is the best way to determine if an argument is an instance of Error?

is the instanceof operator of any help?

5
  • 43
    Yes, use err instanceof Error
    – colecmc
    Commented May 26, 2015 at 21:31
  • 3
    @colecmc won't that be problematic if the error might have come from code in a frame or another window? In that case there will be different prototype Error objects, and instanceof won't work as expected. (see developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/…)
    – Doin
    Commented Aug 30, 2016 at 10:30
  • @Doin, I don't think so. It will just validate the actual error object.
    – colecmc
    Commented Aug 30, 2016 at 17:50
  • 1
    @colecmc, I think you'll find that if you've thrown err in (say) an iframe, but then pass it to the parent window for handing, you'll get (err instanceof Error) === false. That's because the iframe and its parent window have distinct, different Error object prototypes. Similarly an object like obj = {}; will, when passed to a function running in a different window, yeild (obj instanceof Object)===false. (Even worst, in IE, if you keep a reference to obj after its window is destroyed or navigated, trying to call object prototype fns like obj.hasOwnProperty() will throw errors!)
    – Doin
    Commented Aug 31, 2016 at 23:57
  • how do you check for the type of error tho? i.e. catch((err)=>{if (err === ENOENT) returns ENOENT is not defined error?
    – oldboy
    Commented Oct 7, 2019 at 0:44

12 Answers 12

467

You can use the instanceof operator (but see caveat below!).

var myError = new Error('foo');
myError instanceof Error // true
var myString = "Whatever";
myString instanceof Error // false

The above won't work if the error was thrown in a different window/frame/iframe than where the check is happening. In that case, the instanceof Error check will return false, even for an Error object. In that case, the easiest approach is duck-typing.

if (myError && myError.stack && myError.message) {
  // it's an error, probably
}

However, duck-typing may produce false positives if you have non-error objects that contain stack and message properties.

6
  • 2
    @AurélienRibon It works just fine with a ReferenceError instance. You're checking the global ReferenceError object. Try this: try { foo } catch (e) { console.log(e instanceof Error) } It logs true. If you are trying to check the global ReferenceError object for some reason, you can use Error.isPrototypeOf(ReferenceError)
    – Trott
    Commented Sep 18, 2016 at 15:53
  • 1
    @AurélienRibon (Uh, also, yeah, wasn't sure if you were saying "This won't work with a ReferenceError" which is incorrect, or if you were just pointing out "This won't work with the global ReferenceError object" which is absolutely correct, although I'm having a hard time coming up with a situation where one would be checking that, but that may say more about my lack of imagination than the validity of the use case).
    – Trott
    Commented Sep 18, 2016 at 16:09
  • Haha, sorry about that guys, I was just locked into a strange error where all my ReferenceError instances were not instances of Error. This was due to a call to vm.runInNewContext() in node, where all standard prototypes are redefined. All my results were not instances of standard objects. I was looking in SO about this, and fell into this thread :) Commented Sep 20, 2016 at 8:04
  • 2
    You can try const error = (err instanceof Error || err instanceof TypeError) ? err : new Error(err.message ? err.message : err); Commented Jan 3, 2017 at 16:12
  • 1
    @PrimitiveNom myError instanceof SyntaxError or myError instanceof RangeError and so on.
    – Trott
    Commented Oct 31, 2019 at 5:51
44

I asked the original question - @Trott's answer is surely the best.

However with JS being a dynamic language and with there being so many JS runtime environments, the instanceof operator can fail especially in front-end development when crossing boundaries such as iframes. See: https://github.com/mrdoob/three.js/issues/5886

If you are ok with duck typing, this should be good:

let isError = function(e){
   return e && e.stack && e.message;
};

I personally prefer statically typed languages, but if you are using a dynamic language, it's best to embrace a dynamic language for what it is, rather than force it to behave like a statically typed language.

if you wanted to get a little more precise, you could do this:

       let isError = (e) => {
         return e && 
                e.stack && 
                e.message && 
                typeof e.stack === 'string' && 
                typeof e.message === 'string';
        };
8
  • 4
    I prefer this version when writing a utility function or library. It doesn't constrain users to one particular global context and also properly handles deserialized errors from JSON.
    – snickle
    Commented Aug 4, 2017 at 18:03
  • 1
    thanks, yeah in many cases, if it looks like an error, we can treat like an error. in some cases duck typing is totally acceptable, in some cases it's not acceptable at all, in this case, perfectly fine. Commented Aug 4, 2017 at 18:14
  • 1
    I did some debugging using a debugger, and stack and message really do appear to be the only two non-native properties on Error instances. Commented Aug 4, 2017 at 18:16
  • 1
    @Trott you might be interested to know about the instanceof operator failing in some cases, see the linked article. Commented Aug 15, 2017 at 19:54
  • 1
    This is actually the simplest so it works with the different types of errors (i.e. Error, ReferenceError, ...). And in my environment, the instanceof fails miserably in many circumstances. Commented Nov 28, 2018 at 22:23
26

You can use Object.prototype.toString to easily check if an object is an Error, which will work for different frames as well.

function isError(obj){
    return Object.prototype.toString.call(obj) === "[object Error]";
}

function isError(obj){
    return Object.prototype.toString.call(obj) === "[object Error]";
}
console.log("Error:", isError(new Error));
console.log("RangeError:", isError(new RangeError));
console.log("SyntaxError:", isError(new SyntaxError));
console.log("Object:", isError({}));
console.log("Array:", isError([]));

This behavior is guaranteed by the ECMAScript Language Specification.

Object.prototype.toString:

When the toString method is called, the following steps are taken:

  1. If the this value is undefined, return "[object Undefined]".
  2. If the this value is null, return "[object Null]".
  3. Let O be the result of calling ToObject passing the this value as the argument.
  4. Let class be the value of the [[Class]] internal property of O.
  5. Return the String value that is the result of concatenating the three Strings "[object ", class, and "]".

Properties of Error Instances:

Error instances inherit properties from the Error prototype object and their [[Class]] internal property value is "Error". Error instances have no special properties.

4
  • I'm not sure I love this. I don't know if there is any standard that says that when stringified an error has to be exactly of this form. I would think it would depend on the implementation...
    – Aaron
    Commented Oct 13, 2020 at 10:53
  • 3
    @Aaron That's not true. I have edited my answer with excerpts from the ECMAScript Language Specification. Commented Nov 16, 2020 at 15:46
  • 3
    This is the best solution with fewest (none?) downsides.
    – Agendum
    Commented Jul 14, 2021 at 6:18
  • FWIW this is also what isError in @sindresorhus/is does
    – Iris Artin
    Commented Sep 17 at 10:41
21

TypeScript solution

You can define a user-defined type guard, simply need to define a function whose return type is a type predicate

You can check if a variable is error like this

const isError = (err: unknown): err is Error => err instanceof Error;

then inside try catch validate that like this

try {
  login(username, password);
} catch (err) {
  if (isError(err)) {
  console.log(err.message);
}
2
  • 2
    I believe this is a typescript solution. Commented Jan 19, 2022 at 5:18
  • 1
    Note: the caveats from the accepted answer apply the same.
    – John Weisz
    Commented Feb 8, 2023 at 17:33
11
var myError = new Error('foo');
myError instanceof Error // true
var myString = "Whatever";
myString instanceof Error // false

Only problem with this is

myError instanceof Object // true

An alternative to this would be to use the constructor property.

myError.constructor === Object // false
myError.constructor === String // false
myError.constructor === Boolean // false
myError.constructor === Symbol // false
myError.constructor === Function // false
myError.constructor === Error // true

Although it should be noted that this match is very specific, for example:

myError.constructor === TypeError // false
0
6

For those, who're looking for some 'official' way (like I did), this is what MDN recommends:

try {
  myRoutine();
} catch (e) {
  if (e instanceof RangeError) {
    // statements to handle this very common expected error
  } else {
    throw e;  // re-throw the error unchanged
  }
}
3

You can use obj.constructor.name to check the "class" of an object https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/name#Function_names_in_classes

For Example

var error = new Error("ValidationError");
console.log(error.constructor.name);

The above line will log "Error" which is the class name of the object. This could be used with any classes in javascript, if the class is not using a property that goes by the name "name"

1
  • 3
    This is not reliable when minifying code and using error subclasses Commented Aug 27, 2019 at 10:35
2

Just use the error.name

function _err(type = false) {
    if(type) {
        throw new TypeError('Oh crap!')
    }
    throw new Error('Oh crap!')
}

try {
    _err(true)
} catch (error) {
    console.log(typeof error.name, error.name, error.name === 'TypeError', error instanceof Error)
}

try {
    _err()
} catch (error) {
    console.log(typeof error.name, error.name, error.name === 'Error', error instanceof Error)
}

2
  • For RangeError, e.name gives "RangeError" and not "Error". I assume other errors types have different ".name"s. Not very useful.
    – Hezi
    Commented Sep 5, 2023 at 13:02
  • But the base class is Error, so new RangeError() instanceof Error Commented Nov 8, 2023 at 18:26
1

Thanks @Trott for your code, I just used the same code and added with a real time working example for the benefit of others.

<html>
<body >

<p>The **instanceof** operator returns true if the specified object is an instance of the specified object.</p>



<script>
	var myError = new Error("TypeError: Cannot set property 'innerHTML' of null"); // error type when element is not defined
	myError instanceof Error // true
	
	
	
	
	function test(){
	
	var v1 = document.getElementById("myid").innerHTML ="zunu"; // to change with this
	
	try {
		  var v1 = document.getElementById("myidd").innerHTML ="zunu"; // exception caught
		  } 
		  
	catch (e) {
		  if (e instanceof Error) {
			console.error(e.name + ': ' + e.message) // error will be displayed at browser console
		  }
  }
  finally{
		var v1 = document.getElementById("myid").innerHTML ="Text Changed to Zunu"; // finally innerHTML changed to this.
	}
	
	}
	
</script>
<p id="myid">This text will change</p>
<input type="button" onclick="test();">
</body>
</html>

4
  • 2
    Hey, it's 2020 - please don't use var in SO posts
    – refaelio
    Commented Oct 12, 2020 at 11:43
  • @refaelio hey it's 2022, we do our things respectfully, var is still correct in newest versions of JavaScript Commented Apr 6, 2022 at 16:31
  • 1
    Let's just be clear, respectful or not, nobody should ever be using 'var' anymore in modern javascript code. There is no legitimate reason to use 'var' and putting it in stack overflow posts is a very effective way to propagate bad behavior. If you don't believe me, just do a tiny bit of research and you'll see why. There's a reason most linters have a 'no-var' rule.
    – Kelly L
    Commented Aug 24, 2023 at 18:06
  • 1
    Sorry if I was disrespectful. Please note that var is obsolete and should not be used. Use let or const. Keep in mind that answering in stackoverflow has implications on people that are trying to learn and answers like this hinder their progress and confuse them more than anything else.
    – refaelio
    Commented Oct 31, 2023 at 11:25
1

Simply use the following condition:

if (e instanceof ErrorType) { ... }
0

Or use this for different types of errors

function isError(val) {
  return (!!val && typeof val === 'object')
    && ((Object.prototype.toString.call(val) === '[object Error]')
      || (typeof val.message === 'string' && typeof val.name === 'string'))
}
0

You can take the answer from @iota a bit further and check the test object's internal [[Prototype]] property via getPrototypeOf() or the deprecated __proto__ property.

If the object is an error, it inherits from Error.prototype. So maybe something like this:

// the object you want to check 
const objectToCheck = new Error();

// current way
console.log(Object.getPrototypeOf(objectToCheck) === Error.prototype);  /* true*/

// deprecated way
console.log(objectToCheck.__proto__ === Error.prototype);  /* true */

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.