Reputation: 4199
About two months ago we started using Rollbar to notify us of various errors in our Web App. Ever since then we have been getting the occasional error:
ResizeObserver loop limit exceeded
The thing that confuses me about this is that we are not using ResizeObserver
and I have investigated the only plugin which I thought could possibly be the culprit, namely:
But it doesn't appear to be using ResizeObserver
either.
What is also confusing is that these error messages have been occuring since January but ResizeObserver
support has only recently been added to Chrome 65.
The browser versions that have been giving us this error are:
So I was wondering if this could possibly be a browser bug? Or perhaps an error that actually has nothing to do with ResizeObserver
?
Upvotes: 318
Views: 285047
Reputation: 1030
We also had that issue with Monaco Editor because it is using ResizeObserver
internally.
To fix it, we patched the original API by doing:
class CalmResizeObserver extends ResizeObserver {
constructor(callback: ResizeObserverCallback) {
super((entries, observer) => {
requestAnimationFrame(() => {
callback(entries, observer);
});
});
}
}
win.ResizeObserver = CalmResizeObserver;
Upvotes: 3
Reputation: 11
Reactjs
Fix Error: ResizeObserver loop limit exceeded
useEffect(() => {
window.addEventListener('error', e => {enter code here
if (e.message === 'ResizeObserver loop limit exceeded' || e.message === 'Script error.') {
const resizeObserverErrDiv = document.getElementById(
'webpack-dev-server-client-overlay-div'
)
const resizeObserverErr = document.getElementById(
'webpack-dev-server-client-overlay'
)
if (resizeObserverErr) {
resizeObserverErr.setAttribute('style', 'display: none');
}
if (resizeObserverErrDiv) {
resizeObserverErrDiv.setAttribute('style', 'display: none');
}
}
})
}, [])
Upvotes: 1
Reputation: 6412
In Cypress/Jest/Mocha, you can avoid this error with a polyfill:
npm install resize-observer-polyfill --save-dev
Add this to the test:
global.ResizeObserver = require('resize-observer-polyfill');
Upvotes: 0
Reputation: 2359
In my case, I was only interested in changes to an element's width. But changing the element's height during a ResizeObserver event caused a "ResizeObserver loop limit exceeded" error.
To suppress the error, I stopped observing prior to changing the element's size, and started observing again after rendering was complete. Essentially:
const observer = new ResizeObserver(function (entries) {
observer.unobserve(element);
// ...manipulate the element...
setTimeout(function () {
observer.observe(element);
}, 0);
});
The complete solution is here: https://gist.github.com/diachedelic/b026fdd168c8af8cd8ac5cb914e7b3cc.
Upvotes: 1
Reputation: 201
I had this issue with cypress tests not being able to run. I found that instead of handling the exception the proper way was to edit the tsconfig.json in a way to target the new es6 version like so:
{
"extends": "../tsconfig.json",
"compilerOptions": {
"baseUrl": "../node_modules",
"target": "es5", --> old
"target": "es6", --> new
"types": ["cypress", "@testing-library/cypress"],
"sourceMap": true
},
"include": [
"**/*.ts"
]
}
Upvotes: 0
Reputation: 45
Managed to solve this in React for our error logger setup.
The Observer error propagates to the window.onerror
error handler, so by storing the original window.onerror
in a ref, you can then replace it with a custom method that doesn't throw for this particular error. Other errors are allowed to propagate as normal.
Make sure you reconnect the original onerror
in the useEffect
cleanup.
const defaultOnErrorFn = useRef(window.onerror);
useEffect(() => {
window.onerror = (...args) => {
if (args[0] === 'ResizeObserver loop limit exceeded') {
return true;
} else {
defaultOnErrorFn.current && defaultOnErrorFn.current(...args);
}
};
return () => {
window.onerror = defaultOnErrorFn.current;
};
}, []);
Upvotes: 0
Reputation: 2300
One line solution for Cypress. Edit the file support/commands.js with:
Cypress.on(
'uncaught:exception',
(err) => !err.message.includes('ResizeObserver loop limit exceeded')
);
Upvotes: 4
Reputation: 1367
The error might be worth investigating. It can indicate a problem in your code that can be fixed.
In our case an observed resize of an element triggered a change on the page, which caused a resize of the first element again, which again triggered a change on the page, which again caused a resize of the first element, … You know how this ends.
Essentially we created an infinite loop that could not be fitted into a single animation frame, obviously. We broke it by holding up the change on the page using setTimeout()
(although this is not perfect since it may cause some flickering to the users).
So every time ResizeObserver loop limit exceeded
emerges in our Sentry now, we look at it as a useful hint and try to find the cause of the problem.
Upvotes: 9
Reputation: 375
In my case, the issue "ResizeObserver - loop limit exceeded" was triggered because of window.addEventListener("resize"
and React's React.useState
.
In details, I was working on the hook called useWindowResize
where the use case was like this const [windowWidth, windowHeight] = useWindowResize();
.
The code reacts on the windowWidth/windowHeight change via the useEffect.
React.useEffect(() => {
ViewportService.dynamicDimensionControlledBy(
"height",
{ windowWidth, windowHeight },
widgetModalRef.current,
{ bottom: chartTitleHeight },
false,
({ h }) => setWidgetHeight(h),
);
}, [windowWidth, windowHeight, widgetModalRef, chartTitleHeight]);
So any browser window resize caused that issue.
I've found that many similar issues caused because of the connection old-javascript-world (DOM manipulation, browser's events) and the new-javascript-world (React) may be solved by the setTimeout
, but I would to avoid it and call it anti-pattern when possible.
So my fix is to wrap the setter method into the setTimeout function.
React.useEffect(() => {
ViewportService.dynamicDimensionControlledBy(
"height",
{ windowWidth, windowHeight },
widgetModalRef.current,
{ bottom: chartTitleHeight },
false,
({ h }) => setTimeout(() => setWidgetHeight(h), 0),
);
}, [windowWidth, windowHeight, widgetModalRef, chartTitleHeight]);
Upvotes: 2
Reputation: 289
https://github1s.com/chromium/chromium/blob/master/third_party/blink/renderer/core/resize_observer/resize_observer_controller.cc#L44-L45 https://github1s.com/chromium/chromium/blob/master/third_party/blink/renderer/core/frame/local_frame_view.cc#L2211-L2212
After looking at the source code, it seems in my case the issue surfaced when the NotifyResizeObservers function was called, and there were no registered observers.
The GatherObservations function will return a min_depth of 4096, in case there are no observers, and in that case, we will get the "ResizeObserver loop limit exceeded" error.
The way I resolved it is to have an observer living throughout the lifecycle of the page.
Upvotes: 1
Reputation: 143
For Mocha users:
The snippet below overrides the window.onerror hook mocha installs and turns the errors into a warning. https://github.com/mochajs/mocha/blob/667e9a21c10649185e92b319006cea5eb8d61f31/browser-entry.js#L74
// ignore ResizeObserver loop limit exceeded
// this is ok in several scenarios according to
// https://github.com/WICG/resize-observer/issues/38
before(() => {
// called before any tests are run
const e = window.onerror;
window.onerror = function(err) {
if(err === 'ResizeObserver loop limit exceeded') {
console.warn('Ignored: ResizeObserver loop limit exceeded');
return false;
} else {
return e(...arguments);
}
}
});
not sure there is a better way..
Upvotes: 10
Reputation: 291
add debounce like
new ResizeObserver(_.debounce(entries => {}, 200);
fixed this error for me
Upvotes: 7
Reputation: 2104
If you're using Cypress and this issue bumps in, you can safely ignore it in Cypress with the following code in support/index.js or commands.ts
const resizeObserverLoopErrRe = /^[^(ResizeObserver loop limit exceeded)]/
Cypress.on('uncaught:exception', (err) => {
/* returning false here prevents Cypress from failing the test */
if (resizeObserverLoopErrRe.test(err.message)) {
return false
}
})
You can follow the discussion about it here. As Cypress maintainer themselves proposed this solution, so I believe it'd be safe to do so.
Upvotes: 65
Reputation: 269
We had this same issue. We found that a chrome extension was the culprit. Specifically, the loom chrome extension was causing the error (or some interaction of our code with loom extension). When we disabled the extension, our app worked.
I would recommend disabling certain extensions/addons to see if one of them might be contributing to the error.
Upvotes: 11
Reputation: 6782
It's an old question but it still might be helpful to someone. You can avoid this error by wrapping the callback in requestAnimationFrame
.
For example:
const resizeObserver = new ResizeObserver(entries => {
// We wrap it in requestAnimationFrame to avoid this error - ResizeObserver loop limit exceeded
window.requestAnimationFrame(() => {
if (!Array.isArray(entries) || !entries.length) {
return;
}
// your code
});
});
Upvotes: 104
Reputation: 24368
You can safely ignore this error.
One of the specification authors wrote in a comment to your question but it is not an answer and it is not clear in the comment that the answer is really the most important one in this thread, and the one that made me comfortable to ignore it in our Sentry logs.
This error means that ResizeObserver was not able to deliver all observations within a single animation frame. It is benign (your site will not break). – Aleksandar Totic Apr 15 at 3:14
There are also some related issues to this in the specification repository.
Upvotes: 433