IOIIOOIO
IOIIOOIO

Reputation: 4199

ResizeObserver - loop limit exceeded

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:

Aurelia Resize

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

Answers (16)

JoG
JoG

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

Alex Song
Alex Song

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

Noumenon
Noumenon

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

diachedelic
diachedelic

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

perorororo
perorororo

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

DanB-Web
DanB-Web

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

Liko
Liko

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

vasekch
vasekch

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

dominikj111
dominikj111

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

itayad
itayad

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

Jan Kretschmer
Jan Kretschmer

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

Kreja
Kreja

Reputation: 291

add debounce like

new ResizeObserver(_.debounce(entries => {}, 200);

fixed this error for me

Upvotes: 7

Khateeb321
Khateeb321

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

jross
jross

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

Rani
Rani

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

Jacob Rask
Jacob Rask

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

Related Questions