<!DOCTYPE html>
<html>
  <head>
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
  </head>
  <body>
    <p>(Resending this mail since it somehow didn't make it to the
      mailing list the first time)<br>
    </p>
    <p>This issue vanished for us after reworking the application,
      including implementing more fixes for non-platform thread access.
      I can't say definitively whether this caused it, but there were
      some rare instances for us where some properties were changed from
      the wrong thread.</p>
    <br>
    As an easy solution to check the platform thread access for
    everything without having to implement explicit asserts everywhere,
    was a listener-based approach I implemented here: <a
      class="moz-txt-link-freetext"
href="https://mail.openjdk.org/pipermail/openjfx-dev/2025-April/053212.html"
      moz-do-not-send="true">https://mail.openjdk.org/pipermail/openjfx-dev/2025-April/053212.html</a>
    .<br>
    <br>
    <p>It might still be possible that you can encounter this issue just
      using the platform thread as you explained. A better error
      handling of this situation in JavaFX would make this issue already
      less severe. A proper fix to prevent this from happening would be
      even better, but I have no idea how feasible this is. <br>
    </p>
    <p><br>
    </p>
    <div class="moz-cite-prefix">On 25/06/2025 11:06, Dean Wookey wrote:<br>
    </div>
    <blockquote type="cite"
cite="mid:CAKZ_BFhxTEuamPe7i4JFsuRSiA3r3O+z20j9rAaf93ssSAXjOg@mail.gmail.com">
      <meta http-equiv="content-type" content="text/html; charset=UTF-8">
      <div dir="ltr">
        <ol
style="margin:0px;list-style:none;padding:0px;color:rgb(23,43,77);font-family:"DejaVu Sans",sans-serif;font-size:14px">
          Hi Everyone,<br>
          <br>
          We've also been experiencing this problem over the years. It
          seems to be related to JDK-8198577.<br>
          <br>
          Once it goes wrong, each pulse hits the issue repeated meaning
          it can never escape. It's rare, but extremely disruptive when
          it does occur because the user loses what they've been working
          on and has to restart the app.<br>
          <br>
          I've tried really hard to figure out the conditions this
          happens in. I don't think it's a multiple thread issue
          (although for some people it almost certainly could be
          triggered that way) because we've put conditional breakpoints
          that trigger whenever anything that could affect dirty
          children is done off the app thread. We've got assert
          Platform.isFXApplicationThread() all over our app to make sure
          the threading is happening properly.<br>
          <br>
          What I think is happening is that getChildTransformedBounds
          which is being called inside the updateCachedBounds loop, can
          in some rare cases, end up triggering a call to
          updateCachedBounds on the same node. Basically
          updateCachedBounds can call itself recursively. This is a
          snipped from Parent.java in updateCachedBounds.<br>
          <br>
          // this checks the newly added nodes first, so if dirtyNodes
          is the<br>
          // whole children list, we can end early<br>
          for (int i = dirtyNodes.size() - 1; remainingDirtyNodes >
          0; --i) {<br>
             final Node node = dirtyNodes.get(i);<br>
             if (node.boundsChanged) {<br>
                 // assert node.isVisible();<br>
                 node.boundsChanged = false;<br>
                 --remainingDirtyNodes;<br>
                 tmp = getChildTransformedBounds(node,
          BaseTransform.IDENTITY_TRANSFORM, tmp);<br>
          <br>
          In the code above, if this gets called recursively through
          getChildTransformedBounds, then node.boundsChanged will change
          to false for all the nodes which stops remainingDirtyNodes
          from being updated and i eventually goes negative.<br>
          <br>
          We tried to fix the scene graph when this happens by catching
          the exception in the Thread.setDefaultUncaughtExceptionHandler
          but it didn't work. Maybe Christopher's suggested fix would
          work, but as Kevin says "It needs to be tested to ensure that
          when we get the AIOOBE that we can recover. It wouldn't solve
          anything if we catch and log that exception only to have it
          fail shortly after because the scene graph isn't in a good
          state (I don't know whether that would be the case, but it's
          something that needs to be checked)."<br>
          <br>
          Here's how we tried to fix the scene graph when we caught the
          error. The "Fixing IOB Issue" log gets hit all the time, but
          it doesn't find any problems, and in the next pulse it hits
          the problem again with various different stack traces until it
          settles on one. In our latest example of the error, it first
          occurred during a Platform.runLater and not during the pulse,
          but then all subsequent issues happen during the pulse.<br>
          <br>
              protected static void checkSpecialException(Throwable t) {<br>
                  if (t instanceof IndexOutOfBoundsException) {<br>
                      fixIndexOutOfBounds(t);<br>
                  }<br>
              }<br>
          <br>
              public static void fixIndexOutOfBounds(Throwable
          throwable) {<br>
                  FXUtilities.log(EmbraceDesktop.class, <a
            href="http://org.slf4j.event.Level.INFO"
            moz-do-not-send="true">org.slf4j.event.Level.INFO</a>,
          "Fixing IOB Issue");<br>
                  try {<br>
                      Field dirtyChildrenCountField =
          Parent.class.getDeclaredField("dirtyChildrenCount");<br>
                      dirtyChildrenCountField.setAccessible(true);<br>
                      Field dirtyChildrenField =
          Parent.class.getDeclaredField("dirtyChildren");<br>
                      dirtyChildrenField.setAccessible(true);<br>
                      Set<Scene> apps =
          applicationManager.getApplications();<br>
                      ArrayList<Node> brokenStack = new
          ArrayList<>();<br>
                      for (Scene s: apps) {<br>
                          fixTreeRecursive(dirtyChildrenCountField,
          dirtyChildrenField, s.getRoot(), brokenStack);<br>
                      }<br>
                      if (brokenStack.size() > 0) {<br>
                          StringBuilder errorStack = new
          StringBuilder();<br>
                          for (Node n: brokenStack) {<br>
                             
          errorStack.append(n.getClass().getSimpleName() + " " +
          String.join( ",", n.getStyleClass())).append("\n");<br>
                          }<br>
                          EmbraceAnalytics.logCrash("Index out of bounds
          crash",errorStack.toString(), throwable);<br>
                      }<br>
          <br>
          <br>
                  }<br>
                  catch (Throwable t2) {<br>
                      FXUtilities.log(EmbraceDesktop.class,
          org.slf4j.event.Level.ERROR, "Exception while fixing tree",
          t2);<br>
                  }<br>
              }<br>
          <br>
              protected static boolean fixTreeRecursive(Field
          dirtyChildrenCountField, Field dirtyChildrenField, Parent
          parent, ArrayList<Node> brokenStack) throws
          IllegalAccessException {<br>
                  List<?> dirtyChildren = (List<?>)
          dirtyChildrenField.get(parent);<br>
                  int dirtyChildrenCount = (int)
          dirtyChildrenCountField.get(parent);<br>
                  if (dirtyChildren != null) {<br>
                      if (dirtyChildrenCount > dirtyChildren.size())
          {<br>
                          FXUtilities.log(EmbraceDesktop.class,
          org.slf4j.event.Level.ERROR, "Offending node1 was " +
          parent.getClass().getSimpleName());<br>
                          dirtyChildrenCountField.set(parent,
          dirtyChildren.size());<br>
                          brokenStack.add(parent);<br>
                          return true;<br>
                      }<br>
                  }<br>
                  else {<br>
                      if (parent.getChildrenUnmodifiable().size() <
          dirtyChildrenCount) {<br>
                          FXUtilities.log(EmbraceDesktop.class,
          org.slf4j.event.Level.ERROR, "Offending node2 was " +
          parent.getClass().getSimpleName());<br>
                          dirtyChildrenCountField.set(parent,
          parent.getChildrenUnmodifiable().size());<br>
                          brokenStack.add(parent);<br>
                          return true;<br>
                      }<br>
                  }<br>
                  for (Node n: parent.getChildrenUnmodifiable()) {<br>
                      if (n instanceof Parent) {<br>
                          boolean error =
          fixTreeRecursive(dirtyChildrenCountField, dirtyChildrenField,
          (Parent)n, brokenStack);<br>
                          if (error) {<br>
                              brokenStack.add(parent);<br>
                              FXUtilities.log(EmbraceDesktop.class,
          org.slf4j.event.Level.ERROR, "Parent was " +
          parent.getClass().getSimpleName());<br>
                          }<br>
                          return error;<br>
                      }<br>
                  }<br>
                  return false;<br>
              }<br>
          <br>
          I think we should we should put the index check potential fix
          in and log when it happens. As far as we can tell, if this
          issue gets hit, it's catastrophic 100% of the time. The fix
          might resolve the issue. It can't really make it any worse.
          Another thing we should do is add a check for recursive entry
          to that method and log when that occurs. That's (I think) the
          real issue, and without a stack trace of that, it's hard to
          find the root cause.<br>
          <br>
          I don't know if anyone else has experienced this issue and has
          insights/workarounds?<br>
          <br>
          Dean<br>
        </ol>
      </div>
      <br>
      <div class="gmail_quote">
        <div dir="ltr" class="gmail_attr">On Mon, Mar 24, 2025 at
          5:22 PM Christopher Schnick <<a
            href="mailto:crschnick@xpipe.io" target="_blank"
            moz-do-not-send="true" class="moz-txt-link-freetext">crschnick@xpipe.io</a>>
          wrote:<br>
        </div>
        <blockquote class="gmail_quote"
style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">
          <div>
            <p>Hello,<br>
              <br>
              We encountered an issue after updating our application
              implementation to frequently change the visibility of
              nodes. We are essentially now running an implementation
              that very frequently changes the visibility of various
              children nodes based on when they are needed and shown.
              When the user performs a lot of actions, the visibility of
              many nodes will be changed rapidly. <br>
              <br>
              For that, there are many listeners in place that listen
              for bounds changes of nodes to recheck whether they need
              to be made visible or not. All the visibility changes are
              queued up, so they are not immediately done in the
              listener after any bounds changes of parents. They are all
              properly done on the platform thread with runLater. When
              this implementation is running on many client systems, we
              sometimes receive an error report with an exception that
              looks something like this:<br>
              <br>
              java.lang.IndexOutOfBoundsException: Index -1 out of
              bounds for length 2<br>
                  at
java.base/jdk.internal.util.Preconditions.outOfBounds(Preconditions.java:100)<br>
                  at
java.base/jdk.internal.util.Preconditions.outOfBoundsCheckIndex(Preconditions.java:106)<br>
                  at
java.base/jdk.internal.util.Preconditions.checkIndex(Preconditions.java:302)<br>
                  at
              java.base/java.util.Objects.checkIndex(Objects.java:365)<br>
                  at
              java.base/java.util.ArrayList.get(ArrayList.java:428)<br>
                  at <a
href="mailto:javafx.base@25-ea/com.sun.javafx.collections.ObservableListWrapper.get"
                target="_blank" moz-do-not-send="true"
                class="moz-txt-link-freetext">javafx.base@25-ea/com.sun.javafx.collections.ObservableListWrapper.get</a>(ObservableListWrapper.java:88)<br>
                  at <a
href="mailto:javafx.base@25-ea/com.sun.javafx.collections.VetoableListDecorator.get"
                target="_blank" moz-do-not-send="true"
                class="moz-txt-link-freetext">javafx.base@25-ea/com.sun.javafx.collections.VetoableListDecorator.get</a>(VetoableListDecorator.java:326)<br>
                  at <a
href="mailto:javafx.graphics@25-ea/javafx.scene.Parent.updateCachedBounds"
                target="_blank" moz-do-not-send="true"
                class="moz-txt-link-freetext">javafx.graphics@25-ea/javafx.scene.Parent.updateCachedBounds</a>(Parent.java:1769)<br>
                  at <a
href="mailto:javafx.graphics@25-ea/javafx.scene.Parent.recomputeBounds"
                target="_blank" moz-do-not-send="true"
                class="moz-txt-link-freetext">javafx.graphics@25-ea/javafx.scene.Parent.recomputeBounds</a>(Parent.java:1713)<br>
                  at <a
href="mailto:javafx.graphics@25-ea/javafx.scene.Parent.doComputeGeomBounds"
                target="_blank" moz-do-not-send="true"
                class="moz-txt-link-freetext">javafx.graphics@25-ea/javafx.scene.Parent.doComputeGeomBounds</a>(Parent.java:1566)<br>
                  at <a
href="mailto:javafx.graphics@25-ea/javafx.scene.Parent$1.doComputeGeomBounds"
                target="_blank" moz-do-not-send="true"
                class="moz-txt-link-freetext">javafx.graphics@25-ea/javafx.scene.Parent$1.doComputeGeomBounds</a>(Parent.java:116)<br>
                  at <a
href="mailto:javafx.graphics@25-ea/com.sun.javafx.scene.ParentHelper.computeGeomBoundsImpl"
                target="_blank" moz-do-not-send="true"
                class="moz-txt-link-freetext">javafx.graphics@25-ea/com.sun.javafx.scene.ParentHelper.computeGeomBoundsImpl</a>(ParentHelper.java:84)<br>
                  at <a
href="mailto:javafx.graphics@25-ea/com.sun.javafx.scene.layout.RegionHelper.superComputeGeomBoundsImpl"
                target="_blank" moz-do-not-send="true"
                class="moz-txt-link-freetext">javafx.graphics@25-ea/com.sun.javafx.scene.layout.RegionHelper.superComputeGeomBoundsImpl</a>(RegionHelper.java:78)<br>
                  at <a
href="mailto:javafx.graphics@25-ea/com.sun.javafx.scene.layout.RegionHelper.superComputeGeomBounds"
                target="_blank" moz-do-not-send="true"
                class="moz-txt-link-freetext">javafx.graphics@25-ea/com.sun.javafx.scene.layout.RegionHelper.superComputeGeomBounds</a>(RegionHelper.java:62)<br>
                  at <a
href="mailto:javafx.graphics@25-ea/javafx.scene.layout.Region.doComputeGeomBounds"
                target="_blank" moz-do-not-send="true"
                class="moz-txt-link-freetext">javafx.graphics@25-ea/javafx.scene.layout.Region.doComputeGeomBounds</a>(Region.java:3301)<br>
                  at <a
href="mailto:javafx.graphics@25-ea/javafx.scene.layout.Region$1.doComputeGeomBounds"
                target="_blank" moz-do-not-send="true"
                class="moz-txt-link-freetext">javafx.graphics@25-ea/javafx.scene.layout.Region$1.doComputeGeomBounds</a>(Region.java:166)<br>
                  at <a
href="mailto:javafx.graphics@25-ea/com.sun.javafx.scene.layout.RegionHelper.computeGeomBoundsImpl"
                target="_blank" moz-do-not-send="true"
                class="moz-txt-link-freetext">javafx.graphics@25-ea/com.sun.javafx.scene.layout.RegionHelper.computeGeomBoundsImpl</a>(RegionHelper.java:89)<br>
                  at <a
href="mailto:javafx.graphics@25-ea/com.sun.javafx.scene.NodeHelper.computeGeomBounds"
                target="_blank" moz-do-not-send="true"
                class="moz-txt-link-freetext">javafx.graphics@25-ea/com.sun.javafx.scene.NodeHelper.computeGeomBounds</a>(NodeHelper.java:101)<br>
                  at <a
href="mailto:javafx.graphics@25-ea/javafx.scene.Node.updateGeomBounds"
                target="_blank" moz-do-not-send="true"
                class="moz-txt-link-freetext">javafx.graphics@25-ea/javafx.scene.Node.updateGeomBounds</a>(Node.java:3908)<br>
                  at <a
href="mailto:javafx.graphics@25-ea/javafx.scene.Node.getGeomBounds"
                target="_blank" moz-do-not-send="true"
                class="moz-txt-link-freetext">javafx.graphics@25-ea/javafx.scene.Node.getGeomBounds</a>(Node.java:3870)<br>
                  at <a
href="mailto:javafx.graphics@25-ea/javafx.scene.Node.getLocalBounds"
                target="_blank" moz-do-not-send="true"
                class="moz-txt-link-freetext">javafx.graphics@25-ea/javafx.scene.Node.getLocalBounds</a>(Node.java:3818)<br>
                  at <a
href="mailto:javafx.graphics@25-ea/javafx.scene.Node.updateTxBounds"
                target="_blank" moz-do-not-send="true"
                class="moz-txt-link-freetext">javafx.graphics@25-ea/javafx.scene.Node.updateTxBounds</a>(Node.java:3972)<br>
                  at <a
href="mailto:javafx.graphics@25-ea/javafx.scene.Node.getTransformedBounds"
                target="_blank" moz-do-not-send="true"
                class="moz-txt-link-freetext">javafx.graphics@25-ea/javafx.scene.Node.getTransformedBounds</a>(Node.java:3764)<br>
                  at <a
href="mailto:javafx.graphics@25-ea/javafx.scene.Node.updateBounds"
                target="_blank" moz-do-not-send="true"
                class="moz-txt-link-freetext">javafx.graphics@25-ea/javafx.scene.Node.updateBounds</a>(Node.java:828)<br>
                  at <a
href="mailto:javafx.graphics@25-ea/javafx.scene.Parent.updateBounds"
                target="_blank" moz-do-not-send="true"
                class="moz-txt-link-freetext">javafx.graphics@25-ea/javafx.scene.Parent.updateBounds</a>(Parent.java:1900)<br>
                  at <a
href="mailto:javafx.graphics@25-ea/javafx.scene.Scene$ScenePulseListener.pulse"
                target="_blank" moz-do-not-send="true"
                class="moz-txt-link-freetext">javafx.graphics@25-ea/javafx.scene.Scene$ScenePulseListener.pulse</a>(Scene.java:2670)<br>
                  at <a
href="mailto:javafx.graphics@25-ea/com.sun.javafx.tk.Toolkit.runPulse"
                target="_blank" moz-do-not-send="true"
                class="moz-txt-link-freetext">javafx.graphics@25-ea/com.sun.javafx.tk.Toolkit.runPulse</a>(Toolkit.java:380)<br>
                  at <a
href="mailto:javafx.graphics@25-ea/com.sun.javafx.tk.Toolkit.firePulse"
                target="_blank" moz-do-not-send="true"
                class="moz-txt-link-freetext">javafx.graphics@25-ea/com.sun.javafx.tk.Toolkit.firePulse</a>(Toolkit.java:401)<br>
                  at <a
href="mailto:javafx.graphics@25-ea/com.sun.javafx.tk.quantum.QuantumToolkit.pulse"
                target="_blank" moz-do-not-send="true"
                class="moz-txt-link-freetext">javafx.graphics@25-ea/com.sun.javafx.tk.quantum.QuantumToolkit.pulse</a>(QuantumToolkit.java:592)<br>
                  at <a
href="mailto:javafx.graphics@25-ea/com.sun.javafx.tk.quantum.QuantumToolkit.pulse"
                target="_blank" moz-do-not-send="true"
                class="moz-txt-link-freetext">javafx.graphics@25-ea/com.sun.javafx.tk.quantum.QuantumToolkit.pulse</a>(QuantumToolkit.java:572)<br>
                  at <a
href="mailto:javafx.graphics@25-ea/com.sun.javafx.tk.quantum.QuantumToolkit.pulseFromQueue"
                target="_blank" moz-do-not-send="true"
                class="moz-txt-link-freetext">javafx.graphics@25-ea/com.sun.javafx.tk.quantum.QuantumToolkit.pulseFromQueue</a>(QuantumToolkit.java:565)<br>
                  at <a
href="mailto:javafx.graphics@25-ea/com.sun.javafx.tk.quantum.QuantumToolkit.lambda$runToolkit$6"
                target="_blank" moz-do-not-send="true"
                class="moz-txt-link-freetext">javafx.graphics@25-ea/com.sun.javafx.tk.quantum.QuantumToolkit.lambda$runToolkit$6</a>(QuantumToolkit.java:346)<br>
                  at <a
href="mailto:javafx.graphics@25-ea/com.sun.glass.ui.InvokeLaterDispatcher$Future.run$$$capture"
                target="_blank" moz-do-not-send="true"
                class="moz-txt-link-freetext">javafx.graphics@25-ea/com.sun.glass.ui.InvokeLaterDispatcher$Future.run$$$capture</a>(InvokeLaterDispatcher.java:95)<br>
                  at <a
href="mailto:javafx.graphics@25-ea/com.sun.glass.ui.InvokeLaterDispatcher$Future.run"
                target="_blank" moz-do-not-send="true"
                class="moz-txt-link-freetext">javafx.graphics@25-ea/com.sun.glass.ui.InvokeLaterDispatcher$Future.run</a>(InvokeLaterDispatcher.java)<br>
                  <br>
              The index out of bounds is not always the same, there are
              various variations of this. It happens on all operating
              systems. It seems like there is a very specific scenario
              where an index can be out of bounds. This happens very
              rarely, like only a few times out of some hundred
              application runs, so I tried my best at forcing it to
              reproduce.<br>
              <br>
              The following reproducer works most of the time, but it
              might have to be run multiple times. I am aware that it
              eventually results in a StackOverflow, but that was the
              best way to force it reliably, by just continuously
              spamming visibility changes to eventually encounter this
              rare issue. But I want to emphasize that the same error
              also occurs naturally when not being forced like this, but
              it is just a lot more rare. So the StackOverflow in the
              reproducer has nothing to do with this issue, it also
              happens later on.</p>
            <div
style="background-color:rgb(30,31,34);color:rgb(188,190,196)">
              <pre
              style="font-family:"JetBrains Mono",monospace"><span
              style="color:rgb(207,142,109)">import </span>javafx.application.Application;
<span style="color:rgb(207,142,109)">import </span>javafx.scene.Scene;
<span style="color:rgb(207,142,109)">import </span>javafx.scene.control.Button;
<span style="color:rgb(207,142,109)">import </span>javafx.scene.layout.Region;
<span style="color:rgb(207,142,109)">import </span>javafx.scene.layout.StackPane;
<span style="color:rgb(207,142,109)">import </span>javafx.scene.layout.VBox;
<span style="color:rgb(207,142,109)">import </span>javafx.stage.Stage;

<span style="color:rgb(207,142,109)">import </span>java.io.IOException;

<span style="color:rgb(207,142,109)">public class </span>ParentBoundsBug <span
              style="color:rgb(207,142,109)">extends </span>Application {

    <span style="color:rgb(179,174,96)">@Override
</span><span style="color:rgb(179,174,96)">    </span><span
              style="color:rgb(207,142,109)">public void </span><span
              style="color:rgb(86,168,245)">start</span>(Stage stage) <span
              style="color:rgb(207,142,109)">throws </span>IOException {
        Scene scene = <span style="color:rgb(207,142,109)">new </span>Scene(createContent(), <span
              style="color:rgb(42,172,184)">640</span>, <span
              style="color:rgb(42,172,184)">480</span>);
        stage.setScene(scene);
        stage.show();
        stage.centerOnScreen();
    }

    <span style="color:rgb(207,142,109)">private </span>Region <span
              style="color:rgb(86,168,245)">createContent</span>() {
        <span style="color:rgb(207,142,109)">var </span>b1 = <span
              style="color:rgb(207,142,109)">new </span>Button(<span
              style="color:rgb(106,171,115)">"Click me!"</span>);
        <span style="color:rgb(207,142,109)">var </span>b2 = <span
              style="color:rgb(207,142,109)">new </span>Button(<span
              style="color:rgb(106,171,115)">"Click me!"</span>);
        <span style="color:rgb(207,142,109)">var </span>vbox = <span
              style="color:rgb(207,142,109)">new </span>VBox(b1, b2);
        b1.boundsInParentProperty().addListener((observable, oldValue, newValue) -> {
            <span style="color:rgb(199,125,187)">vbox</span>.setVisible(!<span
              style="color:rgb(199,125,187)">vbox</span>.isVisible());
        });
        b2.boundsInParentProperty().addListener((observable, oldValue, newValue) -> {
            <span style="color:rgb(199,125,187)">vbox</span>.setVisible(!<span
              style="color:rgb(199,125,187)">vbox</span>.isVisible());
        });
        vbox.boundsInParentProperty().addListener((observable, oldValue, newValue) -> {
            <span style="color:rgb(199,125,187)">vbox</span>.setVisible(!<span
              style="color:rgb(199,125,187)">vbox</span>.isVisible());
        });

        <span style="color:rgb(207,142,109)">var </span>stack = <span
              style="color:rgb(207,142,109)">new </span>StackPane(vbox, <span
              style="color:rgb(207,142,109)">new </span>StackPane());
        stack.boundsInParentProperty().addListener((observable, oldValue, newValue) -> {
            <span style="color:rgb(199,125,187)">vbox</span>.setVisible(!<span
              style="color:rgb(199,125,187)">vbox</span>.isVisible());
        });
        <span style="color:rgb(207,142,109)">return </span>stack;
    }

    <span style="color:rgb(207,142,109)">public static void </span><span
              style="color:rgb(86,168,245)">main</span>(String[] args) {
        <span style="font-style:italic">launch</span>();
    }
}</pre>
            </div>
            <p><br>
              It doesn't necessarily have something to do with running
              the visibility change directly in the listener, our
              application does a runLater to change the visibility
              state, still with the same results. To properly debug
              this, you will have to launch the reproducer with a bigger
              stack size like -Xss8m to increase the chance that it
              occurs. Then, you can just set a breakpoint at
              jdk.internal.util.Preconditions:302, and wait for it to
              trigger the OOB eventually.<br>
              <br>
              This problem is currently the biggest JavaFX issue for us
              as it breaks the layout and usually requires a restart to
              fix. <br>
              <br>
              Looking at the bounds calculation code, the list index
              bounds check is very optimistic in that it doesn't check
              any indices and relies on multiple assumtions to hold. So
              if it is very difficult to find the cause, a simple index
              bounds check for the list access would also work fine.</p>
            <p>Best<br>
              Christopher Schnick<br>
            </p>
          </div>
        </blockquote>
      </div>
    </blockquote>
  </body>
</html>