Subscribe on changes!

Infinite Loop when trigger ref getter then setter in AppConfig.errorHandler

avatar
Nov 9th 2023

Vue version

Commit 2c0414f (Latest at time of writing)

Link to minimal reproduction

https://play.vuejs.org/#eNp9UsFOIzEM/RUrF1qpSg/cWEDarZCWlRYQcMyBdMbtDGSSKHHKVKP5d5wMFBAIKYfE7/n52c4gfnsvdwnFiTiNVWg9QURK/lzZtvMuEAywRVqlENDSpY2kbYULCLiBETbBdXDE6Ue/lFW2coxDD2cZnv3X1Migbe262XxeCF+VZnOpvV85S9iTZIFNu5UYggt/OdNgYLHZHM7OYVAWoJc7bRKy2OHOhE+VGBtLseUS7ps2Ah9nzR5SxBrIQaX5BtpCKQN1Cq3dsmNbY74tSuZz01YN4I6tJm04e53Wa4MxCzx8Y/NBvrW/Z0M2GcMeTpfTSHmY/CDsvNGE/AIYBtjLNYxjZh0QsRAUX9Ufo7O8ldK2EpXrfMt1rj21XEaJk2kgGWN/7vlfiVFIyA1M8arB6umb+GPsc0yJm4ARww6VOGCkAy9pgi/urngpH8DO1ckw+wfwFqMzKXucaH9SGc8HXnF7Wf4WT/s+XvSENr41lY1m5lj4SvDfWv3Q+rvdY3lc8nj7YnwBhxb3iA==

Steps to reproduce

Upon opening the minimal reproduction link, the playground should immediately show the following error:

Maximum recursive updates exceeded in component <Repl>. This means you have a reactive effect that is mutating its own dependencies and thus recursively triggering itself. Possible sources include component template, render function, updated hook or watcher source function.

What is expected?

No error should occur.

What is actually happening?

It seems that triggering the ref's getter before the setter inside of config.errorHandler causes an infinite loop to occur.

However, if the getter is placed after the setter, the no such infinite loop is entered.

System Info

No response

Any additional comments?

The ref can be a global ref (not instantiated inside of the component) and it seems like the bug still occurs. In the minimal reproduction playground, the ref is created inside <script setup> for simplicity.

EDIT: Something else I forgot to add is that it seems the infinite loop is not entered when using onErrorCaptured, it only happens for config.errorHandler.

avatar
Nov 9th 2023

The reason is that during the execution of the render, it triggered an errorHandler. Therefore, the reactive variables accessed within the errorHandler will also be collected by the render effect. Consequently, modifying reactive variables within the errorHandler will retrigger the render effect. However, at this point, y.b will still throw an error, leading to an infinite loop.

You should handle errors in the errorHandler so that the render can function properly.

playground

avatar
Nov 9th 2023

@Alfred-Skyblue Ah, I did not realize that reactive variables in errorHandler will also be collected by the render effect, thanks for the response!

I guess onErrorCaptured does not enter an infinite loop because internally it calls injectHook, which itself internally calls pauseTracking. This is pretty unintuitive behavior to me but still it makes sense. I guess the question then is whether or not errorHandler should track reactive variables, or if it should pause tracking similar to other lifecycle hooks.

If this is expected behavior (i.e. that errorHandler should track reactive variables) then I think its okay to close this issue.

avatar
Nov 9th 2023

I created a pr to fix it. Of course, if someone has updated the reactive variable in the errorHandler in the past, it may have caused the render to not be updated, but the errorHandler is global and should not be used to update the reactive variable.