<!DOCTYPE html>
<html>
  <head>

    <meta http-equiv="content-type" content="text/html; charset=UTF-8">
  </head>
  <body>
    <p>Hi List,</p>
    <p>This is a bit of a long post. I'm mainly wondering if I did
      something wrong that FX should detect early, or if I'm doing
      nothing unusual and FX should handle the case described below
      correctly.<br>
    </p>
    <p>I encountered the bug where an NPE occurs in
      Scene$ScenePulseListener#synchronizeNodes, and it is reproducable
      at the moment. I'm not sure it is the same one others sometimes
      see, but the version I encountered is prefaced with a failing
      assert (which may easily get lost as synchronizeNodes will spam
      NPE's in your log, as it doesn't recover).</p>
    <p>In Parent#validatePG it prints:</p>
    <p>    *** pgnodes.size validatePG() [1] != children.size() [2]</p>
    <p>And then throws an AssertionError with a long stacktrace.<br>
    </p>
    <p>    java.lang.AssertionError: validation of PGGroup children
      failed<br>
              (stack trace omitted)<br>
    </p>
    <p>Immediately after this, the NPE in synchronizeNodes starts to get
      spammed, and the application never recovers.<br>
    </p>
    <p>This seems to have something to do with nested event loops, as I
      introduced a new one in the code involved.  When I remove the
      nested event loop, there is no problem (it also initially works
      fine when the application is just starting, only in a different
      situation, when there is some user interaction via a keypress,
      does the bug trigger).</p>
    <p>The nested event loop is entered from a ChangeListener, which may
      be a bit unusual.  The documentation of
      Platform#enterNestedEventLoop says:</p>
    <div style="background-color:#ffffff;padding:0px 0px 0px 2px;">
      <div
style="color:#000000;background-color:#ffffff;font-family:"Consolas";font-size:11pt;white-space:pre;"><p
      style="margin:0;"><span style="color:#3f5fbf;">     * This method must either be called from an input event handler or</span></p><p
      style="margin:0;"><span style="color:#3f5fbf;">     * from the run method of a Runnable passed to</span></p><p
      style="margin:0;"><span style="color:#3f5fbf;">     * </span><span
      style="color:#3f3fbf;">{@link javafx.application.Platform#runLater Platform.runLater}</span><span
      style="color:#3f5fbf;">.</span></p><p style="margin:0;"><span
      style="color:#3f5fbf;">     * It must not be called during animation or layout processing.</span></p></div>
    </div>
    <p></p>
    <p>It is also documented to throw an IllegalStateException if used
      incorrectly.  That is however not happening, so I guess I'm using
      it correctly...?  On the other hand, I'm not in an input event
      handler.... the whole process is triggered by a keypress though,
      and deep down in the AssertionError trace you can see:</p>
    <p>    at
com.sun.javafx.event.EventDispatchChainImpl.dispatchEvent(EventDispatchChainImpl.java:114)<br>
          at
      com.sun.javafx.event.EventUtil.fireEventImpl(EventUtil.java:74)<br>
          at com.sun.javafx.event.EventUtil.fireEvent(EventUtil.java:54)<br>
          at javafx.event.Event.fireEvent(Event.java:198)<br>
          at javafx.scene.Scene$KeyHandler.process(Scene.java:4113)<br>
          at javafx.scene.Scene.processKeyEvent(Scene.java:2159)<br>
          at
      javafx.scene.Scene$ScenePeerListener.keyEvent(Scene.java:2627)<br>
          at
com.sun.javafx.tk.quantum.GlassViewEventHandler$KeyEventNotification.run(GlassViewEventHandler.java:218)<br>
      <br>
      So IMHO technically I am in an input event handler...?</p>
    <p>Now the code does a LOT of stuff, which is going to make this
      tough to analyze.  In short:</p>
    <p>- I'm displaying a Scene<br>
      - The user indicates (with a keypress) they want to go to a
      different Pane<br>
      - The previous Pane is created, and added to the scene as a child
      to a TransitionPane that will cross-fade between the current Pane
      and the new Pane<br>
      - As soon as the new Pane becomes part of the Scene, lots of
      things get triggered because the Scene property goes from null to
      the active Scene:<br>
      <br>
          at javafx.scene.Node.invalidatedScenes(Node.java:1075)<br>
          at javafx.scene.Node.setScenes(Node.java:1142)             
      <-- the new Pane will get a Scene assigned to it<br>
          at javafx.scene.Parent$2.onChanged(Parent.java:372)     
      <-- the new Pane has its Parent changed to the TransitionPane<br>
      <br>
      - Several parts of the new Pane listen (directly or indirectly) to
      a change in Scene, as they only become "active" when the Node
      involved is displayed (this happens with a Scene listener)<br>
      - One of those things is some code that will create and populate a
      ListView; this code uses a relatively fast query, but I had marked
      it as something that should be done in the background as it
      sometimes does take a bit too much time on the FX thread</p>
    <p>Now, how I normally do things in the background is to display an
      automatically closing "Please wait" dialog potentially with a
      progress bar on it (this dialog is actually invisible, unless
      sufficient time passes, so in 99% of the cases when things respond
      fast, the user never sees it, even though it was created and is
      there).  This involves starting a nested event loop.  This works
      marvelously throughout this application (and has done so for
      years), and it is used for almost every transition from one part
      of the application to the next.  In all cases so far however I did
      this directly from an event handler.</p>
    <p>So the main difference is that I'm trying to enter a nested event
      loop from a ChangeListener (which deep down was triggered by an
      Event).  In the AssertionError stack trace (which I will include
      at the end), there is no layout or animation code **before**
      entering the nested loop, although there is some layout code
      **after** it was entered.</p>
    <p>I can live with the fact that I may be using enterNestedEventLoop
      incorrectly here, but in that case it should probably also detect
      this incorrect use and throw the IllegalStateException.</p>
    <p>Technically, all this code is triggered while "adding" a Child to
      the TransitionPane, so I suspect that is what the AssertionError
      is about (it indicates the child count 1 != 2, which is what
      TransitionPane has, one active pane, and just added to cross fade
      to).  Still, is this really incorrect usage?</p>
    <p>I've included an annotated stack trace below.</p>
    <p>As it is quite reproducable, I can debug this further by adding
      breakpoints/prints -- I'm just unsure where to start looking.<br>
    </p>
    <p>--John</p>
    <p>java.lang.AssertionError: validation of PGGroup children failed<br>
        at javafx.scene.Parent.validatePG(Parent.java:243)<br>
        at javafx.scene.Parent.doUpdatePeer(Parent.java:201)<br>
        at javafx.scene.Parent$1.doUpdatePeer(Parent.java:109)<br>
        at
      com.sun.javafx.scene.ParentHelper.updatePeerImpl(ParentHelper.java:78)<br>
        at
com.sun.javafx.scene.layout.RegionHelper.updatePeerImpl(RegionHelper.java:72)<br>
        at
      com.sun.javafx.scene.NodeHelper.updatePeer(NodeHelper.java:104)<br>
        at javafx.scene.Node.syncPeer(Node.java:721)<br>
        at
javafx.scene.Scene$ScenePulseListener.synchronizeSceneNodes(Scene.java:2396)<br>
        at javafx.scene.Scene$ScenePulseListener.pulse(Scene.java:2542)<br>
        at com.sun.javafx.tk.Toolkit.lambda$runPulse$2(Toolkit.java:407)<br>
        at
java.base/java.security.AccessController.doPrivileged(AccessController.java:400)<br>
        at com.sun.javafx.tk.Toolkit.runPulse(Toolkit.java:406)<br>
        at com.sun.javafx.tk.Toolkit.firePulse(Toolkit.java:436)<br>
        at
      com.sun.javafx.tk.quantum.QuantumToolkit.pulse(QuantumToolkit.java:575)<br>
        at
      com.sun.javafx.tk.quantum.QuantumToolkit.pulse(QuantumToolkit.java:555)<br>
        at
com.sun.javafx.tk.quantum.QuantumToolkit.pulseFromQueue(QuantumToolkit.java:548)<br>
        at
com.sun.javafx.tk.quantum.QuantumToolkit.lambda$runToolkit$11(QuantumToolkit.java:352)<br>
        at
com.sun.glass.ui.InvokeLaterDispatcher$Future.run(InvokeLaterDispatcher.java:96)<br>
        at
      com.sun.glass.ui.win.WinApplication._enterNestedEventLoopImpl(Native
      Method)<br>
        at
com.sun.glass.ui.win.WinApplication._enterNestedEventLoop(WinApplication.java:211)<br>
        at
      com.sun.glass.ui.Application.enterNestedEventLoop(Application.java:515)<br>
        at com.sun.glass.ui.EventLoop.enter(EventLoop.java:107)<br>
        at
com.sun.javafx.tk.quantum.QuantumToolkit.enterNestedEventLoop(QuantumToolkit.java:631)<br>
        at
      javafx.application.Platform.enterNestedEventLoop(Platform.java:301)<br>
        at
hs.mediasystem.util.javafx.SceneUtil.enterNestedEventLoop(SceneUtil.java:75)  
      <-- just my wrapper to trace slow calls, it delegates to
      Platform<br>
        at
      hs.mediasystem.runner.dialog.DialogPane.showDialog(DialogPane.java:78)<br>
        at
hs.mediasystem.runner.dialog.Dialogs.showProgressDialog(Dialogs.java:163)<br>
        at
      hs.mediasystem.runner.dialog.Dialogs.runNested(Dialogs.java:103)<br>
        at
hs.mediasystem.plugin.home.HomeScreenNodeFactory.lambda$1(HomeScreenNodeFactory.java:123) <br>
    </p>
    <p>The above line is where the nested event loop is entered.  It
      starts to display a "busy" dialog. A background task (on a new
      thread) will create a ListView (this never actually happens, the
      AssertionError is thrown immediately even with an empty task that
      just sleeps 10 seconds).<br>
    </p>
    <p>  at
com.sun.javafx.binding.ExpressionHelper$Generic.fireValueChangedEvent(ExpressionHelper.java:360)<br>
        at
com.sun.javafx.binding.ExpressionHelper.fireValueChangedEvent(ExpressionHelper.java:80)<br>
        at
javafx.beans.property.ReadOnlyObjectPropertyBase.fireValueChangedEvent(ReadOnlyObjectPropertyBase.java:80)<br>
        at
javafx.beans.property.ReadOnlyObjectWrapper.fireValueChangedEvent(ReadOnlyObjectWrapper.java:102)<br>
        at
javafx.beans.property.ObjectPropertyBase.markInvalid(ObjectPropertyBase.java:118)<br>
        at
javafx.beans.property.ObjectPropertyBase.set(ObjectPropertyBase.java:172)<br>
        at
javafx.scene.control.SelectionModel.setSelectedItem(SelectionModel.java:105)<br>
        at
javafx.scene.control.MultipleSelectionModelBase.lambda$new$0(MultipleSelectionModelBase.java:67)<br>
        at
com.sun.javafx.binding.ExpressionHelper$Generic.fireValueChangedEvent(ExpressionHelper.java:348)<br>
        at
com.sun.javafx.binding.ExpressionHelper.fireValueChangedEvent(ExpressionHelper.java:80)<br>
        at
javafx.beans.property.ReadOnlyIntegerPropertyBase.fireValueChangedEvent(ReadOnlyIntegerPropertyBase.java:78)<br>
        at
javafx.beans.property.ReadOnlyIntegerWrapper.fireValueChangedEvent(ReadOnlyIntegerWrapper.java:102)<br>
        at
javafx.beans.property.IntegerPropertyBase.markInvalid(IntegerPropertyBase.java:114)<br>
        at
javafx.beans.property.IntegerPropertyBase.set(IntegerPropertyBase.java:148)<br>
        at
javafx.scene.control.SelectionModel.setSelectedIndex(SelectionModel.java:69)<br>
        at
javafx.scene.control.MultipleSelectionModelBase.select(MultipleSelectionModelBase.java:424)<br>
        at
javafx.scene.control.MultipleSelectionModelBase.select(MultipleSelectionModelBase.java:456)<br>
        at
hs.mediasystem.plugin.home.HomeScreenNodeFactory.lambda$3(HomeScreenNodeFactory.java:176)   
      <-- triggers the creation of a ListView<br>
        at
      javafx.beans.value.ObservableValue.lambda$0(ObservableValue.java:364)<br>
        at
com.sun.javafx.binding.ExpressionHelper$SingleChange.fireValueChangedEvent(ExpressionHelper.java:181)<br>
        at
com.sun.javafx.binding.ExpressionHelper.fireValueChangedEvent(ExpressionHelper.java:80)<br>
        at
      javafx.beans.binding.ObjectBinding.invalidate(ObjectBinding.java:192)<br>
        at
com.sun.javafx.binding.ConditionalBinding.conditionChanged(ConditionalBinding.java:53)<br>
        at
      com.sun.javafx.binding.Subscription.lambda$2(Subscription.java:63)<br>
        at
com.sun.javafx.binding.ExpressionHelper$SingleChange.fireValueChangedEvent(ExpressionHelper.java:181)<br>
        at
com.sun.javafx.binding.ExpressionHelper.fireValueChangedEvent(ExpressionHelper.java:80)<br>
        at
      javafx.beans.binding.ObjectBinding.invalidate(ObjectBinding.java:192)<br>
        at
      com.sun.javafx.binding.Subscription.lambda$4(Subscription.java:83)<br>
        at
com.sun.javafx.binding.ExpressionHelper$SingleInvalidation.fireValueChangedEvent(ExpressionHelper.java:136)<br>
        at
com.sun.javafx.binding.ExpressionHelper.fireValueChangedEvent(ExpressionHelper.java:80)<br>
        at
      javafx.beans.binding.ObjectBinding.invalidate(ObjectBinding.java:192)<br>
        at
      com.sun.javafx.binding.Subscription.lambda$4(Subscription.java:83)<br>
        at
com.sun.javafx.binding.ExpressionHelper$SingleInvalidation.fireValueChangedEvent(ExpressionHelper.java:136)<br>
        at
com.sun.javafx.binding.ExpressionHelper.fireValueChangedEvent(ExpressionHelper.java:80)<br>
        at
      javafx.beans.binding.ObjectBinding.invalidate(ObjectBinding.java:192)<br>
        at
com.sun.javafx.binding.FlatMappedBinding.invalidateAll(FlatMappedBinding.java:102)<br>
        at
      com.sun.javafx.binding.Subscription.lambda$4(Subscription.java:83)<br>
        at
com.sun.javafx.binding.ExpressionHelper$SingleInvalidation.fireValueChangedEvent(ExpressionHelper.java:136)<br>
        at
com.sun.javafx.binding.ExpressionHelper.fireValueChangedEvent(ExpressionHelper.java:80)<br>
        at
      javafx.beans.binding.ObjectBinding.invalidate(ObjectBinding.java:192)<br>
        at
com.sun.javafx.binding.FlatMappedBinding.invalidateAll(FlatMappedBinding.java:102)<br>
        at
      com.sun.javafx.binding.Subscription.lambda$4(Subscription.java:83)<br>
        at
com.sun.javafx.binding.ExpressionHelper$Generic.fireValueChangedEvent(ExpressionHelper.java:348)<br>
        at
com.sun.javafx.binding.ExpressionHelper.fireValueChangedEvent(ExpressionHelper.java:80)<br>
        at
javafx.beans.property.ReadOnlyObjectPropertyBase.fireValueChangedEvent(ReadOnlyObjectPropertyBase.java:80)<br>
        at
javafx.beans.property.ReadOnlyObjectWrapper.fireValueChangedEvent(ReadOnlyObjectWrapper.java:102)<br>
        at
javafx.scene.Node$ReadOnlyObjectWrapperManualFire.fireSuperValueChangedEvent(Node.java:1053)  
      <-- there is a listener on a Scene property<br>
        at javafx.scene.Node.invalidatedScenes(Node.java:1104)<br>
        at javafx.scene.Node.setScenes(Node.java:1142)<br>
        at javafx.scene.Parent.scenesChanged(Parent.java:772)    <--
      the new Pane has a few nested Panes, so you see multiple Parent
      assignments<br>
        at javafx.scene.Node.invalidatedScenes(Node.java:1075)<br>
        at javafx.scene.Node.setScenes(Node.java:1142)<br>
        at javafx.scene.Parent.scenesChanged(Parent.java:772)<br>
        at javafx.scene.Node.invalidatedScenes(Node.java:1075)<br>
        at javafx.scene.Node.setScenes(Node.java:1142)            <--
      the Parent is part of a Scene, so this new Pane also gets the same
      Scene assigned<br>
        at javafx.scene.Parent$2.onChanged(Parent.java:372)    <--
      the new Pane gets its parent assigned (TransitionPane)<br>
        at
com.sun.javafx.collections.TrackableObservableList.lambda$new$0(TrackableObservableList.java:45)<br>
        at
com.sun.javafx.collections.ListListenerHelper$Generic.fireValueChangedEvent(ListListenerHelper.java:329)<br>
        at
com.sun.javafx.collections.ListListenerHelper.fireValueChangedEvent(ListListenerHelper.java:73)<br>
        at
javafx.collections.ObservableListBase.fireChange(ObservableListBase.java:239)<br>
        at
      javafx.collections.ListChangeBuilder.commit(ListChangeBuilder.java:482)<br>
        at
javafx.collections.ListChangeBuilder.endChange(ListChangeBuilder.java:541)<br>
        at
javafx.collections.ObservableListBase.endChange(ObservableListBase.java:211)<br>
        at
javafx.collections.ModifiableObservableListBase.add(ModifiableObservableListBase.java:162)<br>
        at
com.sun.javafx.collections.VetoableListDecorator.add(VetoableListDecorator.java:319)<br>
        at
hs.mediasystem.util.javafx.ui.transition.TransitionPane.add(TransitionPane.java:94)     
      <-- new Pane is added to a TransitionPane that handles cross
      fade between old and new Pane<br>
        at
hs.mediasystem.util.javafx.ui.transition.TransitionPane.addAtStart(TransitionPane.java:105)<br>
        at
hs.mediasystem.util.javafx.ui.transition.TransitionPane.add(TransitionPane.java:113)<br>
        at
hs.mediasystem.runner.presentation.ViewPort.updateChildNode(ViewPort.java:68)      
      <-- here it installs the new Pane to display<br>
        at
      hs.mediasystem.runner.presentation.ViewPort.lambda$0(ViewPort.java:39)<br>
        at
com.sun.javafx.binding.ExpressionHelper$SingleChange.fireValueChangedEvent(ExpressionHelper.java:181)<br>
        at
com.sun.javafx.binding.ExpressionHelper.fireValueChangedEvent(ExpressionHelper.java:80)<br>
        at
      javafx.beans.binding.ObjectBinding.invalidate(ObjectBinding.java:192)<br>
        at
      com.sun.javafx.binding.Subscription.lambda$4(Subscription.java:83)<br>
        at
com.sun.javafx.binding.ExpressionHelper$SingleInvalidation.fireValueChangedEvent(ExpressionHelper.java:136)<br>
        at
com.sun.javafx.binding.ExpressionHelper.fireValueChangedEvent(ExpressionHelper.java:80)<br>
        at
javafx.beans.property.ObjectPropertyBase.fireValueChangedEvent(ObjectPropertyBase.java:111)<br>
        at
javafx.beans.property.ObjectPropertyBase.markInvalid(ObjectPropertyBase.java:118)<br>
        at
javafx.beans.property.ObjectPropertyBase.set(ObjectPropertyBase.java:172)<br>
        at
hs.mediasystem.presentation.ParentPresentation.navigateBack(ParentPresentation.java:39)   
      <-- this handles the keyPress (it was a "back" press)<br>
        at hs.mediasystem.util.expose.Expose.lambda$3(Expose.java:55)<br>
        at hs.mediasystem.util.expose.Trigger$1.run(Trigger.java:58)<br>
        at
hs.mediasystem.runner.RootPresentationHandler.tryRunAction(RootPresentationHandler.java:106)<br>
        at
hs.mediasystem.runner.RootPresentationHandler.handleActionEvent(RootPresentationHandler.java:81)<br>
        at
com.sun.javafx.event.CompositeEventHandler$NormalEventHandlerRecord.handleBubblingEvent(CompositeEventHandler.java:247)<br>
        at
com.sun.javafx.event.CompositeEventHandler.dispatchBubblingEvent(CompositeEventHandler.java:80)<br>
        at
com.sun.javafx.event.EventHandlerManager.dispatchBubblingEvent(EventHandlerManager.java:234)<br>
        at
com.sun.javafx.event.EventHandlerManager.dispatchBubblingEvent(EventHandlerManager.java:191)<br>
        at
com.sun.javafx.event.CompositeEventDispatcher.dispatchBubblingEvent(CompositeEventDispatcher.java:59)<br>
        at
com.sun.javafx.event.BasicEventDispatcher.dispatchEvent(BasicEventDispatcher.java:58)<br>
        at
      hs.mediasystem.util.javafx.SceneUtil.lambda$1(SceneUtil.java:101)     
      <-- this is just my Slow Event detection, and just delegates
      the event<br>
        at
com.sun.javafx.event.EventDispatchChainImpl.dispatchEvent(EventDispatchChainImpl.java:114)<br>
        at
com.sun.javafx.event.BasicEventDispatcher.dispatchEvent(BasicEventDispatcher.java:56)<br>
        at
com.sun.javafx.event.EventDispatchChainImpl.dispatchEvent(EventDispatchChainImpl.java:114)<br>
        at
      com.sun.javafx.event.EventUtil.fireEventImpl(EventUtil.java:74)<br>
        at com.sun.javafx.event.EventUtil.fireEvent(EventUtil.java:49)<br>
        at
      hs.mediasystem.util.javafx.base.Events.dispatchEvent(Events.java:35)<br>
        at
hs.mediasystem.runner.action.InputActionHandler.handleKeyEvent(InputActionHandler.java:153)    
      <-- just code that handles a keypress that bubbled all the way
      to the top<br>
        at
hs.mediasystem.runner.action.InputActionHandler.onKeyPressed(InputActionHandler.java:138)<br>
        at
com.sun.javafx.event.CompositeEventHandler.dispatchBubblingEvent(CompositeEventHandler.java:86)<br>
        at
com.sun.javafx.event.EventHandlerManager.dispatchBubblingEvent(EventHandlerManager.java:234)<br>
        at
com.sun.javafx.event.EventHandlerManager.dispatchBubblingEvent(EventHandlerManager.java:191)<br>
        at
com.sun.javafx.event.CompositeEventDispatcher.dispatchBubblingEvent(CompositeEventDispatcher.java:59)<br>
        at
com.sun.javafx.event.BasicEventDispatcher.dispatchEvent(BasicEventDispatcher.java:58)<br>
        at
      hs.mediasystem.util.javafx.SceneUtil.lambda$1(SceneUtil.java:101)     
      <-- this is just my Slow Event detection, and just delegates
      the event<br>
        at
com.sun.javafx.event.EventDispatchChainImpl.dispatchEvent(EventDispatchChainImpl.java:114)<br>
        at
com.sun.javafx.event.BasicEventDispatcher.dispatchEvent(BasicEventDispatcher.java:56)<br>
        at
com.sun.javafx.event.EventDispatchChainImpl.dispatchEvent(EventDispatchChainImpl.java:114)<br>
        at
      com.sun.javafx.event.EventUtil.fireEventImpl(EventUtil.java:74)<br>
        at com.sun.javafx.event.EventUtil.fireEvent(EventUtil.java:54)<br>
        at javafx.event.Event.fireEvent(Event.java:198)<br>
        at javafx.scene.Scene$KeyHandler.process(Scene.java:4113)<br>
        at javafx.scene.Scene.processKeyEvent(Scene.java:2159)<br>
        at
      javafx.scene.Scene$ScenePeerListener.keyEvent(Scene.java:2627)<br>
        at
com.sun.javafx.tk.quantum.GlassViewEventHandler$KeyEventNotification.run(GlassViewEventHandler.java:218)<br>
        at
com.sun.javafx.tk.quantum.GlassViewEventHandler$KeyEventNotification.run(GlassViewEventHandler.java:150)<br>
        at
java.base/java.security.AccessController.doPrivileged(AccessController.java:400)<br>
        at
com.sun.javafx.tk.quantum.GlassViewEventHandler.lambda$handleKeyEvent$1(GlassViewEventHandler.java:250)<br>
        at
com.sun.javafx.tk.quantum.QuantumToolkit.runWithoutRenderLock(QuantumToolkit.java:424)<br>
        at
com.sun.javafx.tk.quantum.GlassViewEventHandler.handleKeyEvent(GlassViewEventHandler.java:249)<br>
        at com.sun.glass.ui.View.handleKeyEvent(View.java:542)<br>
        at com.sun.glass.ui.View.notifyKey(View.java:966)<br>
        at com.sun.glass.ui.win.WinApplication._runLoop(Native Method)<br>
        at
com.sun.glass.ui.win.WinApplication.lambda$runLoop$3(WinApplication.java:184)<br>
        at java.base/java.lang.Thread.run(Thread.java:1583)<br>
    </p>
    <p>And the NPE exception:</p>
    <p>java.lang.NullPointerException: Cannot invoke
      "javafx.scene.Node.getScene()" because "<local2>" is null<br>
          at
javafx.scene.Scene$ScenePulseListener.synchronizeSceneNodes(Scene.java:2395)<br>
          at
      javafx.scene.Scene$ScenePulseListener.pulse(Scene.java:2542)<br>
          at
      com.sun.javafx.tk.Toolkit.lambda$runPulse$2(Toolkit.java:407)<br>
          at
java.base/java.security.AccessController.doPrivileged(AccessController.java:400)<br>
          at com.sun.javafx.tk.Toolkit.runPulse(Toolkit.java:406)<br>
          (rest of trace identical to the AssertionError one)</p>
    <p>And another variant of the NPE exception:<br>
      <br>
      java.lang.NullPointerException: Cannot invoke
      "javafx.scene.Node.getScene()" because "<local2>" is null<br>
        at
javafx.scene.Scene$ScenePulseListener.synchronizeSceneNodes(Scene.java:2395)<br>
        at javafx.scene.Scene$ScenePulseListener.pulse(Scene.java:2542)<br>
        at com.sun.javafx.tk.Toolkit.lambda$runPulse$2(Toolkit.java:407)<br>
        at
java.base/java.security.AccessController.doPrivileged(AccessController.java:400)<br>
        at com.sun.javafx.tk.Toolkit.runPulse(Toolkit.java:406)<br>
        at com.sun.javafx.tk.Toolkit.firePulse(Toolkit.java:436)<br>
        at
      com.sun.javafx.tk.quantum.QuantumToolkit.pulse(QuantumToolkit.java:575)<br>
        at
      com.sun.javafx.tk.quantum.QuantumToolkit.pulse(QuantumToolkit.java:555)<br>
        at
com.sun.javafx.tk.quantum.QuantumToolkit.pulseFromQueue(QuantumToolkit.java:548)<br>
        at
com.sun.javafx.tk.quantum.QuantumToolkit.lambda$runToolkit$11(QuantumToolkit.java:352)<br>
        at
com.sun.glass.ui.InvokeLaterDispatcher$Future.run(InvokeLaterDispatcher.java:96)<br>
        at com.sun.glass.ui.win.WinApplication._runLoop(Native Method)<br>
        at
com.sun.glass.ui.win.WinApplication.lambda$runLoop$3(WinApplication.java:184)<br>
        at java.base/java.lang.Thread.run(Thread.java:1583)<br>
    </p>
    <p><br>
    </p>
    <p><br>
    </p>
    <p><br>
    </p>
    <p><br>
    </p>
  </body>
</html>