Any thought on what might case `infinite rendering invalidation detected` errors in `renderer.js`?


#1

RWJBlue says,

basically what is happening is that something is throwing an error during rendering

(this should be “ok”, and print the error to the console for you to fix)

when an error occurs during rendering, we cleanup the current rendering transaction (an attempt to avoid other issues when further rendering is needed

however, part of our cleanup for the current transaction is to call didInsertElement and didRender for the things that did get rendered (before the error was thrown)

unfortunately, if you have things that always do a this.set in didInsertElement or didRender then this causes another rendering loop before “settling”

the renderer starts the rendering loop again, but hits the same error as it did the last time

during cleanup of that error the didInsertElement / didRender is called, forcing another render, that render throws, didInsertElement / didRender is called, forcing another render, render throws, :toilet:

:boom: infinite rendering detected

to be clear this is only one possible reason for the infinite rendering detection error, its possible that you actually have a legit bug in the app code that is causing it (edited)

a legit instance of this error would be doing something like this.set('someValueUsedInTemplate', Math.rand()) in didRender :stuck_out_tongue: (since a new random value is always used, every render triggers another render)


#2

I found what was causing my issue. Rather, I found what to remove and the issue no longer happens.

I was testing some rendering times and had [forgotten] that I put this a parent component:

initTime: null,
renderTime: null,

didReceiveAttrs () {
    this._super(...arguments);
    this.set('initTime', new Date().getTime());
},

didRender () {
    this._super(...arguments);
    this.set('renderTime', new Date().getTime());
},

loadTime: computed('initTime', 'renderTime', function() {
    if (isPresent(this.get('initTime')) && isPresent(this.get('renderTime'))) {
        return this.get('renderTime') - this.get('initTime');
    }
    return 0;
})

and in the template:

loadTime: [{{initTime}}][{{renderTime}}][{{loadTime}}]

When I removed that, the issue went away.


#3

Yep, so this is a case of legit infinite rerendering exception (not the failure scenario that I was mentioning earlier). In an async hook, you are invalidating the template that was just rendered (by updating to the current time), which will trigger a rerender. Once that loop happens 10 times, you will get an error.