DEV Community

Raymond Camden
Raymond Camden

Posted on • Originally published at raymondcamden.com on

Handling Errors in Vue.js

I’ve been spending the last year working with, writing about, and presenting on my favorite framework, Vue.js, and realized that I had yet to look into error handling with Vue. I’d like to say that’s because I write perfect code, but I think we all know the truth of that. I spent some time the last few days playing around with various error handling techniques provided by Vue and thought I’d share my findings. Obviously this won’t cover every scenario out there, but I hope it helps!

The Errors!

In order to test out the various error handling techniques, I decided to use three different kinds of errors (initially anyway). The first was simply referring to a variable that doesn’t exist:

<div id="app" v-cloak>
  Hello, {{name}}
</div>

Enter fullscreen mode Exit fullscreen mode

This example will not display an error to the user but will have a [Vue warn] message in the console.

Error messages

You can view this example here:

For a second example, I tried a variable bound to a computed property that would throw an error:

<div id="app" v-cloak>
  Hello, {{name2}}
</div>

<script>
const app = new Vue({
  el:'#app',
  computed:{
    name2() {
      return x;
    }
  }
})
</script>

Enter fullscreen mode Exit fullscreen mode

This throws both a [Vue warn] and a regular error in the console and doesn’t show anything to the user.

Error messages

Here’s an embed for this.

For my third error, I used a method that would throw an error when executed.

<div id="app" v-cloak>
    <button @click="doIt">Do It</button>
</div>

<script>
const app = new Vue({
  el:'#app',
  methods:{
      doIt() {
          return x;
      }
  }
})
</script>

Enter fullscreen mode Exit fullscreen mode

Like the last one, this error will be thrown twice in the console, one warning and one proper error. Unlike last time, the error is only thrown when you actually click the button.

Error with the click handler

And here’s the embed for this one:

Ok, before we go on, I just want to be clear that this isn’t representative of every type of error you can create, it’s just a baseline of a few that I think would be common in Vue.js applications.

So how do you handle errors in Vue applications? I have to say I was a bit surprised that the main Vue Guide did not have a clearly defined section on error handling.

Results for Error

Yes, there is one in the guide, but the text is short enough to fit in a quote:

If a runtime error occurs during a component's render, it will be passed to the global Vue.config.errorHandler config function if it has been set. It might be a good idea to leverage this hook together with an error-tracking service like Sentry, which provides an official integration for Vue.

In my opinion, this topic should really be called out a bit more in the docs. (And frankly that’s on me to see if I can help the docs!) In general, error handling in Vue comes down to these techniques:

  • errorHandler
  • warnHandler
  • renderError
  • errorCaptured
  • window.onerror (not a Vue-specific technique)

Let’s dig in.

Error Handling Technique One: errorHandler

The first technique we’ll look at is errorHandler. As you can probably guess, this is a generic error handler for Vue.js applications. You assign it like so:

Vue.config.errorHandler = function(err, vm, info) {

}

Enter fullscreen mode Exit fullscreen mode

In the function declaration above, err is the actual error object, info is a Vue specific error string, and vm is the actual Vue application. Remember that you can have multiple Vue applications running on one web page at a time. This error handler would apply to all of them. Consider this simple example:

Vue.config.errorHandler = function(err, vm, info) {
  console.log(`Error: ${err.toString()}\nInfo: ${info}`);
}

Enter fullscreen mode Exit fullscreen mode

For the first error, this does nothing. If you remember, it generating a warning, not an error.

For the second error, it handles the error and reports:

Error: ReferenceError: x is not defined
Info: render

Enter fullscreen mode Exit fullscreen mode

Finally, the third example gives this result:

Error: ReferenceError: x is not defined
Info: v-on handler

Enter fullscreen mode Exit fullscreen mode

Note how the info in the two previous examples is pretty helpful. Now let’s check the next technique.

Error Handling Technique Two: warnHandler

The warnHandler handles - wait for it - Vue warnings. Do note though that this handler is ignored during production. The method handler is slightly different as well:

Vue.config.warnHandler = function(msg, vm, trace) {

}

Enter fullscreen mode Exit fullscreen mode

Both msg and vm should be self-explanatory, but trace would be the component tree. Consider this example:

Vue.config.warnHandler = function(msg, vm, trace) {
  console.log(`Warn: ${msg}\nTrace: ${trace}`);
}

Enter fullscreen mode Exit fullscreen mode

The first error example now has a handler for it’s warning and returns:

Warn: Property or method 'name' is not defined on the instance but referenced during render. Make sure that this property is reactive, either in the data option, or for class-based components, by initializing the property. See: https://vuejs.org/v2/guide/reactivity.html#Declaring-Reactive-Properties.
Trace: 

(found in <Root>)

Enter fullscreen mode Exit fullscreen mode

The second and third examples do not change. You can view embeds for all three below:

Error Handling Technique Three: renderError

The third method I’ll demonstrate is renderError. Unlike the previous two, this technique is component specific and not global. Also, like warnHandler, this is disabled in production.

To use, you add it to your component/app. This example is modified from a sample in the docs.

const app = new Vue({
  el:'#app',
  renderError (h, err) {
    return h('pre', { style: { color: 'red' }}, err.stack)
  }
})

Enter fullscreen mode Exit fullscreen mode

If used in the first error example, it does nothing, which if you think about it kinda makes sense as the first one is throwing a warning, not an error. If you test it in the second one where the computed property throws an error, it is rendered. You can see it in the embed below.

To be honest, I’m not sure why I’d use this when the console would be more appropriate, but if your QA team or other testers aren’t familiar with the browser console, having a simpler error message on screen may help.

Error Handling Technique Four: errorCaptured

For the final (Vue-specific) technique, we have errorCaptured, AKA the technique that confused the heck out of me and frankly still confuses me a bit. The docs have this to say:

Called when an error from any descendent component is captured. The hook receives three arguments: the error, the component instance that triggered the error, and a string containing information on where the error was captured. The hook can return false to stop the error from propagating further.

Based on my research (and again, I’m definitely shaky on this), this error handler is only to be used by a “parent” component handling an error from a “child” component. It can’t, as far as I know, be used in a main Vue instance, but only in a component with children.

In order to test this I created a parent/child set of components like so:

Vue.component('cat', {
  template:`
<div><h1>Cat: </h1>
  <slot></slot>
</div>`,
  props:{
    name:{
      required:true,
      type:String
    }
  },
   errorCaptured(err,vm,info) {
    console.log(`cat EC: ${err.toString()}\ninfo: ${info}`); 
     return false;
  }

});

Vue.component('kitten', {
  template:'<div><h1>Kitten: </h1></div>',
  props:{
    name:{
      required:true,
      type:String
    }
  }
});

Enter fullscreen mode Exit fullscreen mode

Notice how the kitten component has an error in it. Now if I try to use it like so:

<div id="app" v-cloak>
  <cat name="my cat">
      <kitten></kitten>
  </cat>
</div>

Enter fullscreen mode Exit fullscreen mode

I’ll get a message from the handler:

cat EC: TypeError: dontexist is not a function
info: render

Enter fullscreen mode Exit fullscreen mode

You can view this in the embed below.

So yeah… interesting feature. I’m guessing it would mostly be used by people building component libraries with parent/child type relationships. More a “library developer” feature than a “regular developer” feature if that makes sense. But again - that’s just my initial impression of the feature.

The One Technique to Rule Them All: window.onerror

Obligatory LOTR reference ring

The final (and most powerful) option is to use window.onerror, a global error handler for anything that can possibly go wrong with your JavaScript. The handler takes the form of:

window.onerror = function(message, source, line, column, error) {

}

Enter fullscreen mode Exit fullscreen mode

Probably the only thing you can’t guess above would be source which is the URL of the script.

Here’s where things get interesting though. If you define this, and do not use Vue.config.errorHandler, then this will not help. Vue expects you to define the darn thing and if you don’t, will not propagate the error outside itself. I … guess that makes sense? I don’t know - to me that doesn’t necessarily make sense. Even odder, let’s say your Vue error handler has an error itself. That won’t propagate to window.onerror either.

Here’s an example CodePen. I’ve commented out the error in the errorHandler, but if you remove the comment, you’ll see the global error handler isn’t run. The only you can see the global handler run is if you click the second button.

Wrap Up

I hope this made sense. As I said in the beginning, this was my first foray into the topic so I’m definitely looking for comments, suggestions, and corrections. I’d love to hear how people are using these techniques in their own apps!

Top comments (9)

Collapse
 
herrbertling profile image
Markus Siering

I think (and am not sure as well 😄) you can compare errorCaptured to React’s error boundaries (=> reactjs.org/docs/error-boundaries....).

So you’d also use them in Vue to capture errors and (through returning false) confine the error to a certain component nesting level. Could be very helpful to shield e.g. network requests within a part of your app from crashing the whole thing… I think 🤔

Collapse
 
raymondcamden profile image
Raymond Camden

Interesting. I don't know React and I keep thinking I need to make the time to get to know it better.

Collapse
 
herrbertling profile image
Markus Siering

Have worked with it before switching jobs and thus starting with Vue. I like Vue way more regarding ease of use. I think it helps to become familiar with React’s basic ideas. A lot is similar to Vue and some things are “further out there” like Suspense and all that fancy stuff 😄

Collapse
 
raymondcamden profile image
Raymond Camden

So that's a good point. I didn't actually show doing something useful with the error capturing. My main point for this article was that aspect though - how to recognize errors from a Vue app. What you do then is... well up to you. In a normal case I'd assume you would show something to the user in a friendly, non-technical manner.

Collapse
 
slidenerd profile image
slidenerd

so based on all the methods above, which one do you use in your Vue apps? I am using Nuxt SSR on my end hence the question

Collapse
 
raymondcamden profile image
Raymond Camden

Honestly I haven't thought about this in some time (and all my Embeds were broken, fixed now!). Probably the app wide errorHandler, but with try/catch in things like fetch() calls.

 
raymondcamden profile image
Raymond Camden

You wouldn't show something to the user? Well you said "specific", but to be clear, I said to tell the user something "friendly, non-technical". I think we're saying the same thing though. :)

Collapse
 
davidsbond profile image
David Bond

Wasn't aware of these error handling hooks for Vue, thanks for the post!

Collapse
 
raymondcamden profile image
Raymond Camden

You are most welcome!