vscode: Error "ResizeObserver loop limit exceeded" when using monaco editor with automaticLayout option

Hello,

We have embedded the monaco-editor (version 0.38.0) in our Angular application, and we are frequently seeing the error “ResizeObserver loop limit exceeded” when we enable option automaticLayout. It does not happen always and depends on the CSS of elements around it.

The error originates from the ResizeObserver which is used within elementSizeObserver.ts. I think it will happen when code that gets executed from the handler results in the resize getting triggered again.

By itself, it seems to be quite harmless, but in our particular setup it can cause some cypress tests to fail. There are ways to work around that as well, but I believe we could avoid this error entirely if we would wrap the handler in requestAnimationFrame(). That would ensure us that the callback will never be called more than once within a single animation frame, and should suffice to avoid the “loop limit exceeded”.

e.g.

public startObserving(): void {
  if (!this._resizeObserver && this._referenceDomElement) {
    this._resizeObserver = new ResizeObserver((entries) => {
      requestAnimationFrame(() => {
        if (entries && entries[0] && entries[0].contentRect) {
          this.observe({ width: entries[0].contentRect.width, height: entries[0].contentRect.height });
        } else {
          this.observe();
        }
      });
    });
    this._resizeObserver.observe(this._referenceDomElement);
  }
}

We have tried this out by patching the monaco-editor package for our application and this confirms that the “loop limit exceeded” error disappears while the automaticLayout functionality keeps working as expected.

I could open a small PR if we think this makes sense? Any thoughts?

About this issue

  • Original URL
  • State: closed
  • Created a year ago
  • Reactions: 10
  • Comments: 26 (9 by maintainers)

Commits related to this issue

Most upvoted comments

@alexdima can we re-open this issue, please? I verified that the PR changes are present with monaco-editor v0.43.0, but the error is not fixed. Also verified once more that with the original fix, the error is gone.

I think the problem with the current version is that we still end up calling this.observe({ width: observeContentRect.width, height: observeContentRect.height }); from the ResizeObserver callback when it fires the 1st time.

Do you see a real problem with simplifying it to something like below?

this._resizeObserver = new ResizeObserver((entries) => {
  const observeContentRect = (entries && entries[0] && entries[0].contentRect ? entries[0].contentRect : null);
  requestAnimationFrame(() => {
    if (observeContentRect) {
      this.observe({ width: observeContentRect.width, height: observeContentRect.height });
    }
    else {
      this.observe();
    }
  });
});
this._resizeObserver.observe(this._referenceDomElement);

When doing it that way, we are indeed always delaying our reaction to the next animation frame, but I think it’s the only way to eliminate the possibility of it firing twice within 1 animation cycle?

@kfrederix thank you for opening this. We started to see it in our react app too. A fix upstream is indeed the best option.

@alexdima any chance you could review this? 😃

Edit: I added another option below, which overwrites the ResizeObserver.

// Save a reference to the original ResizeObserver
const OriginalResizeObserver = window.ResizeObserver;

// Create a new ResizeObserver constructor
window.ResizeObserver = function (callback) {
  const wrappedCallback = (entries, observer) => {
    window.requestAnimationFrame(() => {
      callback(entries, observer);
    });
  };

  // Create an instance of the original ResizeObserver
  // with the wrapped callback
  return new OriginalResizeObserver(wrappedCallback);
};

// Copy over static methods, if any
for (let staticMethod in OriginalResizeObserver) {
  if (OriginalResizeObserver.hasOwnProperty(staticMethod)) {
    window.ResizeObserver[staticMethod] = OriginalResizeObserver[staticMethod];
  }
}

Agreed - 0.43 does not fix it

We use monaco inside a single page app written in Elm. We use monaco on a page you get indrectly via the landing page. Our production version does not exhibit the issue, but it is constantly present in our dev environment

As noted below the error is ResizeObserver loop completed with undelivered notifications.

How do we track when this gets into monaco?

Thank you @erropix for removing all the noise from the repro! Your PR is merged.

(strange thing is: I started really minimal with something similar to this but could not get the error. But I’m happy you found the trick!)

@alexdima fyi: you can find the minimal repro here: https://github.com/kfrederix/monaco-resizeobserver-error

@alexdima would you agree to re-open this issue, since it’s not yet solved and we have a repro available?

Or if you don’t agree, I would still be interested to hear your thoughts on this 🙏

@kfrederix Were you able to find a fix for this one? I see the same thing in my react app where I try to set the layout like below . If I comment this code out, the error is gone.

editor.onDidContentSizeChange(() => {
      setHeight(Math.min(1000, editor.getContentHeight()));
      editor.layout();
    });

Thank you, @kfrederix, for providing the template. I was able to remove some code while maintaining the error. I sent you a pull request.

@erropix Can you please provide a simple repro demonstrating the problem?

@kfrederix Same for me, I disabled automaticLayout option, and used a custom resize observer to call editor.layout() function.

@kfrederix @simonh1000 Can you please provide a repro

it might be some changes in chrome 115 https://bugs.chromium.org/p/chromium/issues/detail?id=1467390&q=resize observer&can=2&sort=-modified

wrapping in raf is an option, but it has some downsides

  1. can delay handler execution
  2. this error is there to prevent infinite resize loops, raf approach would “hide” this error

one option for the time being might be just catching this error on the window and console.log it with some message once

Hi, I can confirm it. We’ve been having this annoying problem for some time in dev and finally found the root cause. Can you please consider taking a look at it?

(opened the PR already… all feedback is welcome!)