mithril.js: Error handling in view

It seems like Mithril does not handle errors thrown in the view function.

My personal experience is that if an error is thrown inside the view, the UI does not get properly updated. Not only the component fails to be updated, but the entire app as well.

Context

In this example, an error is thrown inside ErrorComp.view. The error prevents UI update in the entire app, hence button label is not updated.

var data = {
  flag: true
}

var ErrorComp = {
  view: function () {
    console.log(data.flag)
    return (data.flag ?
      `No error.`
      :
      undefined.error
    )
  }
}

var App = {
  view: function () {
    return [
      m(ErrorComp),
      m('div', 'Click the button below.'),
      m('button', { onclick: () => data.flag = !data.flag },
        'Toggle flag: ' + data.flag
      )
    ]
  }
}

m.mount(document.getElementById('app'), App)

Fiddle here.

Steps

  1. Click the button.

Expected

ErrorComp not to render, but the rest of the application to update (button label to show false).

Actual

The UI does not update.

Suggestion

Mithril could catch the error and render an empty string where the component should be (and log the error). Maybe an errorView method could be supported (if defined).

It is all too easy to get an error in a component. For example if part of a data path is undefined, as loaded from AJAX. I think keeping the rest of the UI up to date would result in a more robust application. One that I as a developer can trust will work in the wild.

I know I can work around this, and I do. But I think Mithril could do better, and be more friendly to devs.

About this issue

  • Original URL
  • State: open
  • Created 7 years ago
  • Comments: 34 (23 by maintainers)

Most upvoted comments

I’m not really sure that if the best solution would be to update 98% of views or not, there may be an argument for easier detection of something going seriously wrong if everything goes seriously wrong.

The surprising part of the sample fiddle was IMO that there was no error logged, rethrowing at the end of the redraw cycle would probably be ideal.

@orbitbot I put a typeof console !== 'undefined', the fewer window references in the code base, the better.

Regardless of whether a more sophisticated catch equivalent is developed or not, silently handling the error (“The surprising part of the sample fiddle was IMO that there was no error logged”) hardly seems desirable behavior. Perhaps ‘Expected’ behavior should be extended to explicitly include both points – (1) rest of the app updates and (2) the error logged or otherwise made visible to the calling function?

@orbitbot yes it would hence my remark. We could wrap the console.error call in a try/catch block. User facing behavior would be consistent. (And the devs would get the messages when they open the console).

@pygy, @barneycarroll, and I came up with a plan.

Here’s the concerns I believe need addressed when it comes to fault tolerance in Mithril, in decreasing priority:

  • Mithril shouldn’t break over user errors
  • Mithril shouldn’t hide user errors
  • Mithril shouldn’t let caught user errors affect unrelated components
  • Mithril shouldn’t allow potentially invalid state to be used
  • Mithril shouldn’t let resource leaks propagate
  • Mithril shouldn’t prevent error recovery

The first two bullets will be the focus of this bug, but the other 4 will be discussed in #2273.

Resolving the first 2 will mean this flems should log oninit + oncreate and this flems should log oninit + oncreate + onbeforeupdate + onupdate. (Currently the first logs just oninit and the second logs oninit + oninit + oncreate.)

Hi, folks. I’d like to report a subtler wrinkle to this issue: under v1.1.6 if the first render of a component throws an error, it is caught and logged, but it leaves the vnode in a state where it will throw confusing errors about ‘onbeforeupdate’ in subsequent renders, with most likely serious impact on app behavior. See https://jsfiddle.net/v2dL1cLw/2/ This does not appear to be an issue in next, but I’m mentioning it (other than as a historical curiosity) because 1.1.6 is still the most current stable release.

@nandoflorestan Also, could you file a new issue WRT that? This is about allowing optional opt-in graceful handling of errors. (Currently, if any errors are being swallowed within the framework, that’s a bug.)

Differently from some here, I do not want any error catching at all. In my application, I would prefer the entire page to crash if anything goes wrong. In fact, I consider half-working pages to be a very bad and confusing thing for users and for bug squashing in general. PHP practices notwithstanding.

Anyway, as much as I love mithril, it is creating a debugging nightmare by swallowing any exceptions thrown in my components (in the constructor or in the view method). Putting something on the console is the very least that mithril must do.

This is the most urgent fix that mithtril needs IMO. Someone said using “next” has this problem mitigated. Where can I read about what the consequences of using “next” are?

Although this is so urgent, it has lingered here for months. Could someone do something?

@isiahmeadows Calling lifecycle methods would be awesome! A lot better than I can do today!