You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Many of our views can open non-modal dialogs. When navigating to another view, these dialogs should be closed. Therefore, these views call Dialog.close in their onDetach hooks.
However, if some component inside the dialog also overrides onDetach and calls DetachEvent.getUI, this leads to NoSuchElementException when the whole browser tab is closed. The reason is that the dialog is detached twice in this case: once explicitely by our view, and once implicitely by Vaadin when detaching the whole component tree. Thus, when detached for the second time, the component has actually already been detached, so you cannot get a UI.
Interestingly, onDetach itself is always only called once at some later point, not inside Dialog.close, but the problem does not arise when not calling close.
Expected behavior
Inside an onDetach hook, DetachEvent.getUI should never throw. When all components are detached anyway, an additional Dialog.close should only affect the order in which detach hooks are called.
2024-12-12T10:53:09.406+01:00 WARN 37612 --- [p1096116778-107] o.e.jetty.ee10.servlet.ServletChannel : /
jakarta.servlet.ServletException: Request processing failed: java.util.NoSuchElementException: No value present
at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:1022) ~[spring-webmvc-6.1.14.jar:6.1.14]
at org.springframework.web.servlet.FrameworkServlet.doPost(FrameworkServlet.java:914) ~[spring-webmvc-6.1.14.jar:6.1.14]
at jakarta.servlet.http.HttpServlet.service(HttpServlet.java:547) ~[jakarta.servlet-api-6.0.0.jar:6.0.0]
at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:885) ~[spring-webmvc-6.1.14.jar:6.1.14]
at jakarta.servlet.http.HttpServlet.service(HttpServlet.java:614) ~[jakarta.servlet-api-6.0.0.jar:6.0.0]
at org.eclipse.jetty.ee10.servlet.ServletHolder.handle(ServletHolder.java:736) ~[jetty-ee10-servlet-12.0.14.jar:12.0.14]
at org.eclipse.jetty.ee10.servlet.ServletHandler$ChainEnd.doFilter(ServletHandler.java:1614) ~[jetty-ee10-servlet-12.0.14.jar:12.0.14]
at org.eclipse.jetty.ee10.websocket.servlet.WebSocketUpgradeFilter.doFilter(WebSocketUpgradeFilter.java:195) ~[jetty-ee10-websocket-servlet-12.0.14.jar:12.0.14]
at org.eclipse.jetty.ee10.servlet.FilterHolder.doFilter(FilterHolder.java:205) ~[jetty-ee10-servlet-12.0.14.jar:12.0.14]
at org.eclipse.jetty.ee10.servlet.ServletHandler$Chain.doFilter(ServletHandler.java:1586) ~[jetty-ee10-servlet-12.0.14.jar:12.0.14]
at org.springframework.web.filter.RequestContextFilter.doFilterInternal(RequestContextFilter.java:100) ~[spring-web-6.1.14.jar:6.1.14]
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116) ~[spring-web-6.1.14.jar:6.1.14]
at org.eclipse.jetty.ee10.servlet.FilterHolder.doFilter(FilterHolder.java:205) ~[jetty-ee10-servlet-12.0.14.jar:12.0.14]
at org.eclipse.jetty.ee10.servlet.ServletHandler$Chain.doFilter(ServletHandler.java:1586) ~[jetty-ee10-servlet-12.0.14.jar:12.0.14]
at org.springframework.web.filter.FormContentFilter.doFilterInternal(FormContentFilter.java:93) ~[spring-web-6.1.14.jar:6.1.14]
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116) ~[spring-web-6.1.14.jar:6.1.14]
at org.eclipse.jetty.ee10.servlet.FilterHolder.doFilter(FilterHolder.java:205) ~[jetty-ee10-servlet-12.0.14.jar:12.0.14]
at org.eclipse.jetty.ee10.servlet.ServletHandler$Chain.doFilter(ServletHandler.java:1586) ~[jetty-ee10-servlet-12.0.14.jar:12.0.14]
at org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:201) ~[spring-web-6.1.14.jar:6.1.14]
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116) ~[spring-web-6.1.14.jar:6.1.14]
at org.eclipse.jetty.ee10.servlet.FilterHolder.doFilter(FilterHolder.java:205) ~[jetty-ee10-servlet-12.0.14.jar:12.0.14]
at org.eclipse.jetty.ee10.servlet.ServletHandler$Chain.doFilter(ServletHandler.java:1586) ~[jetty-ee10-servlet-12.0.14.jar:12.0.14]
at org.eclipse.jetty.ee10.servlet.ServletHandler$MappedServlet.handle(ServletHandler.java:1547) ~[jetty-ee10-servlet-12.0.14.jar:12.0.14]
at org.eclipse.jetty.ee10.servlet.ServletChannel.dispatch(ServletChannel.java:824) ~[jetty-ee10-servlet-12.0.14.jar:12.0.14]
at org.eclipse.jetty.ee10.servlet.ServletChannel.handle(ServletChannel.java:436) ~[jetty-ee10-servlet-12.0.14.jar:12.0.14]
at org.eclipse.jetty.ee10.servlet.ServletHandler.handle(ServletHandler.java:464) ~[jetty-ee10-servlet-12.0.14.jar:12.0.14]
at org.eclipse.jetty.security.SecurityHandler.handle(SecurityHandler.java:575) ~[jetty-security-12.0.14.jar:12.0.14]
at org.eclipse.jetty.ee10.servlet.SessionHandler.handle(SessionHandler.java:717) ~[jetty-ee10-servlet-12.0.14.jar:12.0.14]
at org.eclipse.jetty.server.handler.ContextHandler.handle(ContextHandler.java:1060) ~[jetty-server-12.0.14.jar:12.0.14]
at org.eclipse.jetty.server.Server.handle(Server.java:182) ~[jetty-server-12.0.14.jar:12.0.14]
at org.eclipse.jetty.server.internal.HttpChannelState$HandlerInvoker.run(HttpChannelState.java:662) ~[jetty-server-12.0.14.jar:12.0.14]
at org.eclipse.jetty.server.internal.HttpConnection.onFillable(HttpConnection.java:414) ~[jetty-server-12.0.14.jar:12.0.14]
at org.eclipse.jetty.io.AbstractConnection$ReadCallback.succeeded(AbstractConnection.java:322) ~[jetty-io-12.0.14.jar:12.0.14]
at org.eclipse.jetty.io.FillInterest.fillable(FillInterest.java:99) ~[jetty-io-12.0.14.jar:12.0.14]
at org.eclipse.jetty.io.SelectableChannelEndPoint$1.run(SelectableChannelEndPoint.java:53) ~[jetty-io-12.0.14.jar:12.0.14]
at org.eclipse.jetty.util.thread.strategy.AdaptiveExecutionStrategy.runTask(AdaptiveExecutionStrategy.java:478) ~[jetty-util-12.0.14.jar:12.0.14]
at org.eclipse.jetty.util.thread.strategy.AdaptiveExecutionStrategy.consumeTask(AdaptiveExecutionStrategy.java:441) ~[jetty-util-12.0.14.jar:12.0.14]
at org.eclipse.jetty.util.thread.strategy.AdaptiveExecutionStrategy.tryProduce(AdaptiveExecutionStrategy.java:293) ~[jetty-util-12.0.14.jar:12.0.14]
at org.eclipse.jetty.util.thread.strategy.AdaptiveExecutionStrategy.run(AdaptiveExecutionStrategy.java:201) ~[jetty-util-12.0.14.jar:12.0.14]
at org.eclipse.jetty.util.thread.ReservedThreadExecutor$ReservedThread.run(ReservedThreadExecutor.java:311) ~[jetty-util-12.0.14.jar:12.0.14]
at org.eclipse.jetty.util.thread.QueuedThreadPool.runJob(QueuedThreadPool.java:979) ~[jetty-util-12.0.14.jar:12.0.14]
at org.eclipse.jetty.util.thread.QueuedThreadPool$Runner.doRunJob(QueuedThreadPool.java:1209) ~[jetty-util-12.0.14.jar:12.0.14]
at org.eclipse.jetty.util.thread.QueuedThreadPool$Runner.run(QueuedThreadPool.java:1164) ~[jetty-util-12.0.14.jar:12.0.14]
at java.base/java.lang.Thread.run(Thread.java:1583) ~[na:na]
Caused by: java.util.NoSuchElementException: No value present
at java.base/java.util.Optional.get(Optional.java:143) ~[na:na]
at com.vaadin.flow.component.internal.AbstractAttachDetachEvent.getUI(AbstractAttachDetachEvent.java:50) ~[flow-server-24.5.5.jar:24.5.5]
at com.asaon.views.detach.DetachIssue$1.onDetach(DetachIssue.java:25) ~[classes/:na]
at com.vaadin.flow.component.ComponentUtil.onComponentDetach(ComponentUtil.java:341) ~[flow-server-24.5.5.jar:24.5.5]
at java.base/java.util.Optional.ifPresent(Optional.java:178) ~[na:na]
at com.vaadin.flow.internal.nodefeature.ComponentMapping.onDetach(ComponentMapping.java:109) ~[flow-server-24.5.5.jar:24.5.5]
at java.base/java.util.stream.ForEachOps$ForEachOp$OfRef.accept(ForEachOps.java:184) ~[na:na]
at java.base/java.util.stream.ReferencePipeline$2$1.accept(ReferencePipeline.java:179) ~[na:na]
at java.base/java.util.Spliterators$ArraySpliterator.forEachRemaining(Spliterators.java:1024) ~[na:na]
at java.base/java.util.stream.AbstractPipeline.copyInto(AbstractPipeline.java:509) ~[na:na]
at java.base/java.util.stream.AbstractPipeline.wrapAndCopyInto(AbstractPipeline.java:499) ~[na:na]
at java.base/java.util.stream.ForEachOps$ForEachOp.evaluateSequential(ForEachOps.java:151) ~[na:na]
at java.base/java.util.stream.ForEachOps$ForEachOp$OfRef.evaluateSequential(ForEachOps.java:174) ~[na:na]
at java.base/java.util.stream.AbstractPipeline.evaluate(AbstractPipeline.java:234) ~[na:na]
at java.base/java.util.stream.ReferencePipeline.forEach(ReferencePipeline.java:596) ~[na:na]
at com.vaadin.flow.internal.StateNode.forEachFeature(StateNode.java:377) ~[flow-server-24.5.5.jar:24.5.5]
at com.vaadin.flow.internal.StateNode.fireDetachListeners(StateNode.java:944) ~[flow-server-24.5.5.jar:24.5.5]
at com.vaadin.flow.internal.StateNode.onDetach(StateNode.java:354) ~[flow-server-24.5.5.jar:24.5.5]
at com.vaadin.flow.internal.StateNode.setParent(StateNode.java:289) ~[flow-server-24.5.5.jar:24.5.5]
at com.vaadin.flow.internal.StateTree$RootNode.setParent(StateTree.java:68) ~[flow-server-24.5.5.jar:24.5.5]
at com.vaadin.flow.component.internal.UIInternals.setSession(UIInternals.java:430) ~[flow-server-24.5.5.jar:24.5.5]
at com.vaadin.flow.server.VaadinSession.removeUI(VaadinSession.java:664) ~[flow-server-24.5.5.jar:24.5.5]
at com.vaadin.flow.server.VaadinService.lambda$removeClosedUIs$20ed7015$1(VaadinService.java:1400) ~[flow-server-24.5.5.jar:24.5.5]
at com.vaadin.flow.component.UI.accessSynchronously(UI.java:498) ~[flow-server-24.5.5.jar:24.5.5]
at com.vaadin.flow.component.UI.accessSynchronously(UI.java:459) ~[flow-server-24.5.5.jar:24.5.5]
at com.vaadin.flow.server.VaadinService.removeClosedUIs(VaadinService.java:1398) ~[flow-server-24.5.5.jar:24.5.5]
at com.vaadin.flow.server.VaadinService.cleanupSession(VaadinService.java:1361) ~[flow-server-24.5.5.jar:24.5.5]
at com.vaadin.flow.server.VaadinService.requestEnd(VaadinService.java:1571) ~[flow-server-24.5.5.jar:24.5.5]
at com.vaadin.flow.server.VaadinService.handleRequest(VaadinService.java:1664) ~[flow-server-24.5.5.jar:24.5.5]
at com.vaadin.flow.server.VaadinServlet.service(VaadinServlet.java:398) ~[flow-server-24.5.5.jar:24.5.5]
at com.vaadin.flow.spring.SpringServlet.service(SpringServlet.java:106) ~[vaadin-spring-24.5.5.jar:na]
at jakarta.servlet.http.HttpServlet.service(HttpServlet.java:614) ~[jakarta.servlet-api-6.0.0.jar:6.0.0]
at org.eclipse.jetty.ee10.servlet.ServletHolder.handle(ServletHolder.java:736) ~[jetty-ee10-servlet-12.0.14.jar:12.0.14]
at org.eclipse.jetty.ee10.servlet.ServletHandler$ChainEnd.doFilter(ServletHandler.java:1614) ~[jetty-ee10-servlet-12.0.14.jar:12.0.14]
at org.eclipse.jetty.ee10.servlet.ServletHandler$MappedServlet.handle(ServletHandler.java:1547) ~[jetty-ee10-servlet-12.0.14.jar:12.0.14]
at org.eclipse.jetty.ee10.servlet.Dispatcher.forward(Dispatcher.java:126) ~[jetty-ee10-servlet-12.0.14.jar:12.0.14]
at org.springframework.web.servlet.mvc.ServletForwardingController.handleRequestInternal(ServletForwardingController.java:142) ~[spring-webmvc-6.1.14.jar:6.1.14]
at org.springframework.web.servlet.mvc.AbstractController.handleRequest(AbstractController.java:178) ~[spring-webmvc-6.1.14.jar:6.1.14]
at org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter.handle(SimpleControllerHandlerAdapter.java:51) ~[spring-webmvc-6.1.14.jar:6.1.14]
at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:1089) ~[spring-webmvc-6.1.14.jar:6.1.14]
at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:979) ~[spring-webmvc-6.1.14.jar:6.1.14]
at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:1014) ~[spring-webmvc-6.1.14.jar:6.1.14]
... 43 common frames omitted
The outer one depends on the servlet container, which is Jetty in my case. But the cause shows that the exception happens when removing the UI in requestEnd.
On another note, I wonder if such an error shouldn't be passed to VaadinSession.getErrorHandler. Currently, it simply bubbles up to the servlet container, which apparently simply logs it as a warning. We usually don't enable these loggers, so we didn't know about this exception, even though the issue probably exists for quite some time. I can open a separate issue for this if you like.
The main workaround I've found is to avoid calling dialog.close if the UI is closing:
protectedvoidonDetach(DetachEventdetachEvent) {
if (dialog != null && !detachEvent.getUI().isClosing())
dialog.close();
}
Versions
Vaadin / Flow version: 24.5.5
Java version: Eclipse Temurin 21.0.5
OS version: Windows 11
The text was updated successfully, but these errors were encountered:
I haven't thought about that, that would probably work here. But navigation is just one example where the outer component is detached. But there are other scenarios where the outer component is detached without navigation. For example, it could simply be removed from a parent component for whatever reason. Or, it could itself be embedded in an outer dialog, which you can close manually.
By hooking into onDetach, the outer component doesn't need to know why it is detached, so this is more reusable.
Description of the bug
Many of our views can open non-modal dialogs. When navigating to another view, these dialogs should be closed. Therefore, these views call
Dialog.close
in theironDetach
hooks.However, if some component inside the dialog also overrides
onDetach
and callsDetachEvent.getUI
, this leads toNoSuchElementException
when the whole browser tab is closed. The reason is that the dialog is detached twice in this case: once explicitely by our view, and once implicitely by Vaadin when detaching the whole component tree. Thus, when detached for the second time, the component has actually already been detached, so you cannot get a UI.Interestingly,
onDetach
itself is always only called once at some later point, not insideDialog.close
, but the problem does not arise when not callingclose
.Expected behavior
Inside an onDetach hook,
DetachEvent.getUI
should never throw. When all components are detached anyway, an additionalDialog.close
should only affect the order in which detach hooks are called.Minimal reproducible example
You see an exception that looks similar to this:
The outer one depends on the servlet container, which is Jetty in my case. But the cause shows that the exception happens when removing the UI in
requestEnd
.On another note, I wonder if such an error shouldn't be passed to
VaadinSession.getErrorHandler
. Currently, it simply bubbles up to the servlet container, which apparently simply logs it as a warning. We usually don't enable these loggers, so we didn't know about this exception, even though the issue probably exists for quite some time. I can open a separate issue for this if you like.The main workaround I've found is to avoid calling
dialog.close
if the UI is closing:Versions
The text was updated successfully, but these errors were encountered: