vaadin / flow

Vaadin Flow is a Java framework binding Vaadin web components to Java. This is part of Vaadin 10+.
Apache License 2.0
621 stars 167 forks source link

Vaadin application throws exception upon screen refresh #15436

Open Gary02g opened 1 year ago

Gary02g commented 1 year ago

Description of the bug

Application starts as expected and display proper content. However, when 'Reload the page' button is clicked on the browser application crashes with the following log messages: 2022-12-11 19:56:04.638 ERROR 104388 --- [nio-8080-exec-5] c.v.flow.router.InternalServerError : There was an exception while trying to navigate to ''

java.lang.IllegalStateException: Can't move a node from one state tree to another. If this is intentional, first remove the node from its current state tree by calling removeFromTree at com.vaadin.flow.internal.StateNode.doSetTree(StateNode.java:739) ~[flow-server-23.2.8.jar:23.2.8] at com.vaadin.flow.internal.StateNode.lambda$setTree$3(StateNode.java:380) ~[flow-server-23.2.8.jar:23.2.8] at com.vaadin.flow.internal.StateNode.visitNodeTree(StateNode.java:688) ~[flow-server-23.2.8.jar:23.2.8] I have posted the problem on StackOverflow but no useful advice was given. My application does not have any static components whatsoever, according to the similar messages on SO. As stack trace does not contain any mentioning of my code, it is impossible to identify any potential problems in the application. It is a complete showstopper.

Expected behavior

Application shall redisplay the content without crashing.

Minimal reproducible example

My application contain over 50 Java classes with 10000+ lines of code. As I cannot identify where error occurs, It is impossible to provide minimal reproducible example. Especially, as my code is not involved in producing this exception.

Versions

mcollovati commented 1 year ago

Hi, thanks for reporting. It is hard to say what may cause the issue without additional information. From the description, I suppose your application is using PreserveOnRefresh feature. Is there any chance that references to UI components are held by attach listeners or something similar? Does the problem happen on every view or only on some of them? Did you try to put a breakpoint in StateNode.doSetTree() method to detect what component is failing? May I also ask you to post the full stacktrace?

Legioth commented 1 year ago

Another thing to look for is if there's any Vaadin component that is used as a Spring or CDI bean with a scope that is too wide (e.g. singleton or session scoped).

Gary02g commented 1 year ago

There are several Vaadin components that are used as Spring beans. However, all of them are annotated as prototypes. @Configuration @Lazy public class PanelsConfig {

@Autowired ApiBookUtils api; 

@Bean
@Scope("prototype")
public AccountPanel getUserPanel(Reader user) {
    return new AccountPanel(user);
}

@Bean
@Scope("prototype")
public AccountPanel getAdminPanel(Reader user) {
    return new AccountPanel(user, true);
}

@Bean
@Scope("prototype")
public FilterPanel getFilterPanel() {
    return new FilterPanel(api);
}

@Bean
@Scope("prototype")
public BookPanel getBookPanel() {
    return new BookPanel(api);
}

@Bean
@Scope("prototype")
public BookContextMenu getBookContextMenu() {
    return new BookContextMenu(this);
}

@Bean
@Scope("prototype")
public ReviewPanel getReviewPanel() {
    return new ReviewPanel(api);
}

} Therefore, the scope of those beans aren't wide.

Gary02g commented 1 year ago

Exception occurs on a regular basis upon screen refresh. Here is latest stack trace: 2022-12-18 21:23:26.170 ERROR 32152 --- [nio-8080-exec-7] c.v.flow.router.InternalServerError : There was an exception while trying to navigate to ''

java.lang.IllegalStateException: Can't move a node from one state tree to another. If this is intentional, first remove the node from its current state tree by calling removeFromTree at com.vaadin.flow.internal.StateNode.doSetTree(StateNode.java:739) ~[flow-server-23.2.8.jar:23.2.8] at com.vaadin.flow.internal.StateNode.lambda$setTree$3(StateNode.java:380) ~[flow-server-23.2.8.jar:23.2.8] at com.vaadin.flow.internal.StateNode.visitNodeTree(StateNode.java:688) ~[flow-server-23.2.8.jar:23.2.8] at com.vaadin.flow.internal.StateNode.setTree(StateNode.java:380) ~[flow-server-23.2.8.jar:23.2.8] at com.vaadin.flow.internal.StateNode.setParent(StateNode.java:274) ~[flow-server-23.2.8.jar:23.2.8] at com.vaadin.flow.internal.nodefeature.NodeFeature.attachPotentialChild(NodeFeature.java:80) ~[flow-server-23.2.8.jar:23.2.8] at com.vaadin.flow.internal.nodefeature.StateNodeNodeList.add(StateNodeNodeList.java:55) ~[flow-server-23.2.8.jar:23.2.8] at com.vaadin.flow.internal.nodefeature.ElementChildrenList.add(ElementChildrenList.java:44) ~[flow-server-23.2.8.jar:23.2.8] at com.vaadin.flow.dom.impl.AbstractNodeStateProvider.insertChild(AbstractNodeStateProvider.java:104) ~[flow-server-23.2.8.jar:23.2.8] at com.vaadin.flow.dom.Node.insertChild(Node.java:386) ~[flow-server-23.2.8.jar:23.2.8] at com.vaadin.flow.dom.Node.appendChild(Node.java:163) ~[flow-server-23.2.8.jar:23.2.8] at com.vaadin.flow.dom.Node.appendChild(Node.java:147) ~[flow-server-23.2.8.jar:23.2.8] at com.vaadin.flow.component.internal.JavaScriptBootstrapUI$JavaScriptUIInternalUpdater.updateRoot(JavaScriptBootstrapUI.java:422) ~[flow-server-23.2.8.jar:23.2.8] at com.vaadin.flow.component.internal.UIInternals.showRouteTarget(UIInternals.java:769) ~[flow-server-23.2.8.jar:23.2.8] at com.vaadin.flow.router.internal.AbstractNavigationStateRenderer.handle(AbstractNavigationStateRenderer.java:229) ~[flow-server-23.2.8.jar:23.2.8] at com.vaadin.flow.component.internal.JavaScriptNavigationStateRenderer.handle(JavaScriptNavigationStateRenderer.java:78) ~[flow-server-23.2.8.jar:23.2.8] at com.vaadin.flow.component.internal.JavaScriptBootstrapUI.handleNavigation(JavaScriptBootstrapUI.java:317) ~[flow-server-23.2.8.jar:23.2.8] at com.vaadin.flow.component.internal.JavaScriptBootstrapUI.renderViewForRoute(JavaScriptBootstrapUI.java:280) ~[flow-server-23.2.8.jar:23.2.8] at com.vaadin.flow.component.internal.JavaScriptBootstrapUI.connectClient(JavaScriptBootstrapUI.java:147) ~[flow-server-23.2.8.jar:23.2.8] at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:na] at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) ~[na:na] at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[na:na] at java.base/java.lang.reflect.Method.invoke(Method.java:564) ~[na:na] at com.vaadin.flow.server.communication.rpc.PublishedServerEventHandlerRpcHandler.invokeMethod(PublishedServerEventHandlerRpcHandler.java:222) ~[flow-server-23.2.8.jar:23.2.8] at com.vaadin.flow.server.communication.rpc.PublishedServerEventHandlerRpcHandler.invokeMethod(PublishedServerEventHandlerRpcHandler.java:199) ~[flow-server-23.2.8.jar:23.2.8] at com.vaadin.flow.server.communication.rpc.PublishedServerEventHandlerRpcHandler.invokeMethod(PublishedServerEventHandlerRpcHandler.java:149) ~[flow-server-23.2.8.jar:23.2.8] at com.vaadin.flow.server.communication.rpc.PublishedServerEventHandlerRpcHandler.handleNode(PublishedServerEventHandlerRpcHandler.java:132) ~[flow-server-23.2.8.jar:23.2.8] at com.vaadin.flow.server.communication.rpc.AbstractRpcInvocationHandler.handle(AbstractRpcInvocationHandler.java:75) ~[flow-server-23.2.8.jar:23.2.8] at com.vaadin.flow.server.communication.ServerRpcHandler.handleInvocationData(ServerRpcHandler.java:438) ~[flow-server-23.2.8.jar:23.2.8] at com.vaadin.flow.server.communication.ServerRpcHandler.lambda$handleInvocations$1(ServerRpcHandler.java:419) ~[flow-server-23.2.8.jar:23.2.8] at java.base/java.util.ArrayList.forEach(ArrayList.java:1511) ~[na:na] at com.vaadin.flow.server.communication.ServerRpcHandler.handleInvocations(ServerRpcHandler.java:419) ~[flow-server-23.2.8.jar:23.2.8] at com.vaadin.flow.server.communication.ServerRpcHandler.handleRpc(ServerRpcHandler.java:320) ~[flow-server-23.2.8.jar:23.2.8] at com.vaadin.flow.server.communication.UidlRequestHandler.synchronizedHandleRequest(UidlRequestHandler.java:115) ~[flow-server-23.2.8.jar:23.2.8] at com.vaadin.flow.server.SynchronizedRequestHandler.handleRequest(SynchronizedRequestHandler.java:40) ~[flow-server-23.2.8.jar:23.2.8] at com.vaadin.flow.server.VaadinService.handleRequest(VaadinService.java:1564) ~[flow-server-23.2.8.jar:23.2.8] at com.vaadin.flow.server.VaadinServlet.service(VaadinServlet.java:369) ~[flow-server-23.2.8.jar:23.2.8] at com.vaadin.flow.spring.SpringServlet.service(SpringServlet.java:106) ~[vaadin-spring-23.2.8.jar:na] at javax.servlet.http.HttpServlet.service(HttpServlet.java:764) ~[tomcat-embed-core-9.0.65.jar:4.0.FR] at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:227) ~[tomcat-embed-core-9.0.65.jar:9.0.65] at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:162) ~[tomcat-embed-core-9.0.65.jar:9.0.65] at org.apache.catalina.core.ApplicationDispatcher.invoke(ApplicationDispatcher.java:711) ~[tomcat-embed-core-9.0.65.jar:9.0.65] at org.apache.catalina.core.ApplicationDispatcher.processRequest(ApplicationDispatcher.java:459) ~[tomcat-embed-core-9.0.65.jar:9.0.65] at org.apache.catalina.core.ApplicationDispatcher.doForward(ApplicationDispatcher.java:353) ~[tomcat-embed-core-9.0.65.jar:9.0.65] at org.apache.catalina.core.ApplicationDispatcher.forward(ApplicationDispatcher.java:313) ~[tomcat-embed-core-9.0.65.jar:9.0.65] at org.springframework.web.servlet.mvc.ServletForwardingController.handleRequestInternal(ServletForwardingController.java:141) ~[spring-webmvc-5.3.23.jar:5.3.23] at org.springframework.web.servlet.mvc.AbstractController.handleRequest(AbstractController.java:177) ~[spring-webmvc-5.3.23.jar:5.3.23] at org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter.handle(SimpleControllerHandlerAdapter.java:51) ~[spring-webmvc-5.3.23.jar:5.3.23] at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:1071) ~[spring-webmvc-5.3.23.jar:5.3.23] at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:964) ~[spring-webmvc-5.3.23.jar:5.3.23] at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:1006) ~[spring-webmvc-5.3.23.jar:5.3.23] at org.springframework.web.servlet.FrameworkServlet.doPost(FrameworkServlet.java:909) ~[spring-webmvc-5.3.23.jar:5.3.23] at javax.servlet.http.HttpServlet.service(HttpServlet.java:681) ~[tomcat-embed-core-9.0.65.jar:4.0.FR] at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:883) ~[spring-webmvc-5.3.23.jar:5.3.23] at javax.servlet.http.HttpServlet.service(HttpServlet.java:764) ~[tomcat-embed-core-9.0.65.jar:4.0.FR] at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:227) ~[tomcat-embed-core-9.0.65.jar:9.0.65] at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:162) ~[tomcat-embed-core-9.0.65.jar:9.0.65] at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:53) ~[tomcat-embed-websocket-9.0.65.jar:9.0.65] at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:189) ~[tomcat-embed-core-9.0.65.jar:9.0.65] at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:162) ~[tomcat-embed-core-9.0.65.jar:9.0.65] at org.springframework.web.filter.RequestContextFilter.doFilterInternal(RequestContextFilter.java:100) ~[spring-web-5.3.23.jar:5.3.23] at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:117) ~[spring-web-5.3.23.jar:5.3.23] at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:189) ~[tomcat-embed-core-9.0.65.jar:9.0.65] at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:162) ~[tomcat-embed-core-9.0.65.jar:9.0.65] at org.springframework.web.filter.FormContentFilter.doFilterInternal(FormContentFilter.java:93) ~[spring-web-5.3.23.jar:5.3.23] at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:117) ~[spring-web-5.3.23.jar:5.3.23] at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:189) ~[tomcat-embed-core-9.0.65.jar:9.0.65] at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:162) ~[tomcat-embed-core-9.0.65.jar:9.0.65] at org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:201) ~[spring-web-5.3.23.jar:5.3.23] at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:117) ~[spring-web-5.3.23.jar:5.3.23] at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:189) ~[tomcat-embed-core-9.0.65.jar:9.0.65] at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:162) ~[tomcat-embed-core-9.0.65.jar:9.0.65] at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:197) ~[tomcat-embed-core-9.0.65.jar:9.0.65] at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:97) ~[tomcat-embed-core-9.0.65.jar:9.0.65] at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:541) ~[tomcat-embed-core-9.0.65.jar:9.0.65] at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:135) ~[tomcat-embed-core-9.0.65.jar:9.0.65] at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:92) ~[tomcat-embed-core-9.0.65.jar:9.0.65] at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:78) ~[tomcat-embed-core-9.0.65.jar:9.0.65] at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:360) ~[tomcat-embed-core-9.0.65.jar:9.0.65] at org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:399) ~[tomcat-embed-core-9.0.65.jar:9.0.65] at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:65) ~[tomcat-embed-core-9.0.65.jar:9.0.65] at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:890) ~[tomcat-embed-core-9.0.65.jar:9.0.65] at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1789) ~[tomcat-embed-core-9.0.65.jar:9.0.65] at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:49) ~[tomcat-embed-core-9.0.65.jar:9.0.65] at org.apache.tomcat.util.threads.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1191) ~[tomcat-embed-core-9.0.65.jar:9.0.65] at org.apache.tomcat.util.threads.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:659) ~[tomcat-embed-core-9.0.65.jar:9.0.65] at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61) ~[tomcat-embed-core-9.0.65.jar:9.0.65] at java.base/java.lang.Thread.run(Thread.java:832) ~[na:na]

mcollovati commented 1 year ago

I tried to reproduce the issue, but unsuccessfully. Injecting prototype components into a view works correctly on page reload for me and can't see any exception. I tried it with and without @PreserveOnRefresh.

@Gary02g could you set up a minimal reproducible example, for example in a new project created with start.vaadin.com?

Gary02g commented 1 year ago

My project include 30+ classes with over 10K lines of code. I don't know what is causing this exception, because in the stack trace there is no mentioning of my code at all. Therefore, I don't know how to create minimal reproducible example. Can you provide more information in throwing exception message. I tried to catch it in the debugger, but wasn't able even to find the class com.vaadin.flow.internal.StateNode in my dependency tree. What jar file it is contained in? What is @PreserveOnRefresh? I didn't see this annotation in the Vaadin docs. I am relatively new to it (about 3 months). Where it shall be used?

mcollovati commented 1 year ago

@PreserveOnRefresh is a feature that allows you to keep UI state when page is reloaded (https://vaadin.com/docs/latest/advanced/preserving-state-on-refresh), but it is highly probable that you do not need it.

StateNode is in flow-server jar.

Does you Route annotated views perhaps have some spring Scope annotation? Or are you defining Route views as spring beans?

Gary02g commented 1 year ago

My application is a single page with several dialogs. I have only one class annotated with @Route. Here is the code: @PageTitle("Энциклопедия") @Route(value = "") public class EncyclopediaMainLayout extends VerticalLayout {

private final  HeaderLayout header;
private final  TableLayout table;

public EncyclopediaMainLayout(@Autowired HeaderLayout hdr, @Autowired TableLayout tbl) {
    this.header = hdr;
    this.table = tbl;
    add(header, table);
}    

} Do you see anything suspicious in it?

Gary02g commented 1 year ago

I added @PreserveOnRefresh to the main layout and it is not crashing on screen refresh anymore. I will keep testing and hope it won't crash anymore. However, you definitely need to improve diagnostic. At the very least your exception message shall point to offending class and say why it is happening.

mcollovati commented 1 year ago

Do you see anything suspicious in it?

The only particular thing I can notice is the injection of UI components, but if they have prototype scope it should work (if they do not have references to other components in a different scope).

It should be interesting to check if the two injected components are already attached to a different UI, by adding a break point before the add(...) calls, and check if getElement().getNode().getOwner() references a NullOwner for the hdr and tbl. If not, it means there is something wrong with the injected components, potentially not been new clean instances.

Edit: of course, the check should be done without @PreserveOnRefresh

However, you definitely need to improve diagnostic

This is definitely something we can try to improve

FiruzzZ commented 11 months ago

The improved message exception was added to Vaadin 24.2.x+, why? moving from V23 to 24 is not a simple task, have to upgrade spring boot 3, jdk17, node_modules and frontend folder change the structure (not compatible with v23), jakarta EE and so on https://github.com/vaadin/flow/pull/18019

Legioth commented 11 months ago

Enhancements are built for the latest version and only backported to older versions if there's some very specific reason to do so. Otherwise, we would end up spending lots of time backporting old enhancements and have little time left for creating new enhancements.