java.lang.IllegalStateException: Lookup instance is not found in VaadinContext

I have been developing my Vaadin application for about 6 months and recently I noticed that it has started producing the below log messages every few seconds. I am not sure when I actually started, but I guess it was in the last 1-2 weeks.

My App is using the latest Vaadin version 24.7 and is a PWA with Push enabled. My Application class extends the class as suggested in the error message. The messages are occurring during runtime of the application, so I do not know why I would look at the Unit tests.

I am not sure what research I should be doing to stop these messages now?

at com.vaadin.hilla.route.RouteUtil.isRouteAllowed(RouteUtil.java:64)

I find the above line regarding Hilla in the stack trace to be strange. I am not using Hilla at all in this project.

public class Application extends SpringBootServletInitializer implements AppShellConfigurator, VaadinServiceInitListener {

Mar 20, 2025 9:22:32 AM org.apache.catalina.core.StandardWrapperValve invoke

SEVERE: Servlet.service() for servlet [dispatcherServletRegistration] in context with path [] threw exception

java.lang.IllegalStateException: The application Lookup instance is not found in VaadinContext. The instance is supposed to be created by a ServletContainerInitializer. Issues known to cause this problem are:

- A Spring Boot application deployed as a war-file but the main application class does not extend SpringBootServletInitializer

- An embedded server that is not set up to execute ServletContainerInitializers

- Unit tests which do not properly set up the context for the test

at com.vaadin.flow.server.startup.ApplicationConfiguration.lambda$get$0(ApplicationConfiguration.java:53)

at com.vaadin.flow.server.VaadinServletContext.getAttribute(VaadinServletContext.java:73)

at com.vaadin.flow.server.startup.ApplicationConfiguration.get(ApplicationConfiguration.java:47)

at com.vaadin.hilla.route.RouteUtil.isRouteAllowed(RouteUtil.java:64)

at com.vaadin.flow.spring.security.RequestUtil.isAllowedHillaView(RequestUtil.java:123)

at org.springframework.security.web.util.matcher.RequestMatcher.matcher(RequestMatcher.java:48)

at org.springframework.security.web.access.intercept.RequestMatcherDelegatingAuthorizationManager.check(RequestMatcherDelegatingAuthorizationManager.java:82)

…

at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1743)

at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:52)

at org.apache.tomcat.util.threads.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1190)

at org.apache.tomcat.util.threads.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:659)

at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:63)

at java.base/java.lang.Thread.run(Thread.java:1583)

Since your application class is extending SpringBootServletInitializer I suppose you are building a war and deploying it into an external servlet container.
Can you provide additional information about the setup? Which servlet container are you using and which version?
Spring security is enabled, and it looks like you are using VaadinWebSecurity to configure it, right?
Do you happen to remember which Vaadin version worked for you?
Does the error happen at startup? Or is it somehow related to hot-reload of Java changes and server restarts?

Hi Marco, I was not always extending SpringBootServletInitializer, I only added that as the error messages is telling me to do that. I created the application originally from the start.vaadin.com website in August of last year. The Application class has the @SpringBootApplication annotation on it.

My Security configuration looks like this (after removing some company specific includes):

public class SecurityConfiguration extends VaadinWebSecurity {

@Override
protected void configure(HttpSecurity http) throws Exception {

    final String homeUrl = "<url goes here>";
    final String tenantId = "<tenant id goes here>"

    http.authorizeHttpRequests(authorize -> authorize
            .requestMatchers("/icons/**", "/pwa-manifest.json", "/*.json")
            .permitAll()) // Allow access to icons, static resources and manifest.json files
        .oauth2Login(customizer -> customizer
            .redirectionEndpoint(epConfig -> epConfig.baseUri("/login/**"))
            .userInfoEndpoint(ep -> ep.oidcUserService(customOidcUserService()))
            .failureHandler((req, resp, exception) -> {
                String errorMessage = "Login failed :[%s]".formatted(exception.getMessage());
                log.error(errorMessage, exception);
                resp.setStatus(401);
                resp.getWriter().write(errorMessage);
            }))
        .logout(logoutConfigurer -> logoutConfigurer
            .logoutUrl("/logout")
            .logoutSuccessUrl("https://login.microsoftonline.com/%s/oauth2/logout?post_logout_redirect_uri=%s".formatted(tenantId, homeUrl))
            .invalidateHttpSession(true)
            .deleteCookies("JSESSIONID"));
    super.configure(http);
}

private OAuth2UserService<OidcUserRequest, OidcUser> customOidcUserService() {
    final OidcUserService delegate = new OidcUserService();
    return userRequest -> {
        OidcUser oidcUser = delegate.loadUser(userRequest);
        Collection<GrantedAuthority> grantedAuthorities = CollectionUtils.union(oidcUser.getAuthorities(), GroupsClaimMapper.mapAuthorities(oidcUser));

        // Remote call to short code mapper
        String userShortCode = mapper.mapUser(oidcUser.getClaimAsString(SAM_ACCOUNT_NAME_CLAIM_KEY));

        // Store the JWT IdToken in the user's session
        idTokenPersistenceService.setInitialToken(userRequest.getIdToken().getTokenValue(), glencoreUserShortCode);

        return new FXMOidcUser(grantedAuthorities, oidcUser.getIdToken(), oidcUser.getUserInfo(), "name", userShortCode);
    };
}

}

I am using the following setup which I got from my logs:

Starting Servlet engine: [Apache Tomcat/10.1.36]
“Running with Spring Boot v3.4.3, Spring v6.2.3”,
"Starting Application using Java 21.0.6
“Devtools property defaults active! Set ‘spring.devtools.add-properties’ to ‘false’ to disable”
“Installed AtmosphereHandler com.vaadin.hilla.push.PushEndpoint mapped to context-path: /HILLA/push”
“Installed the following AtmosphereInterceptor mapped to AtmosphereHandler com.vaadin.hilla.push.PushEndpoint”

The problem only happens when deployed to our K8s environment. Locally during development in the IDE the problem does not show in the logs.
I am using the hot-reload mode locally for development.

The problem starts immediately after starting the application on the remote server after these log entries:

`INFO: Initializing Spring DispatcherServlet ‘dispatcherServletRegistration’ “message”:“Initializing Servlet ‘dispatcherServletRegistration’”
“message”:“Completed initialization in 1 ms”,

I do not know which version it was last working correctly, I would have to do a lot of testing and research to find that out.

You only need to extend SpringBootServletInitializer if you are packaging the app as a WAR file and deploying it to an external container.

A Spring Boot application deployed as a war-file

So, assuming you are bulding a Spring Boot app wiht an embedded servlet container, I would suggest you to remove it.

Did you make a production build before deploying on Kubernetes?
You should have built the application with the production profile active, e.g. mvn package -Pproduction

Hi Marco,

I have removed the use of the ‘SpringBootServletInitializer’ class.

Yes, we always build and deploy the app with the -Pproduction flag set.

On a side note: I upgraded to the latest version of Vaadin 24.7 it see if it would fix my problem, and it was a disaster. Everything went very very slow and random page reloads, so I have downgraded back to 24.6.7

That’s really weird and annoying.
Could you post full logs (server and browser) so that we can try to understand what’s going on?

Hi Marco, we are currently reverting several changes on the deployment, and therefore I am waiting until we get a stable environment to send logs. I will need to revert to older version to see when this problem started and then I can see what changed to cause the problem.

I will post the logs as soon as I have them.

Hi Marco, I noticed that you had responded to a similar thread on the github about the same problem but no one had responded to you:

I was told to stop looking at this problem and focus on the business deliveries :cry: Now my colleague is able to investigate this now and I will get him to do some research and post his findings here.

We still have this problem and my colleague should be able to get some logs and useful configs, etc …

1 Like

Hi Marco,

Regarding the initial error mentioned in this thread:

SEVERE: Servlet.service() for servlet [dispatcherServletRegistration] in context with path [] threw exception

java.lang.IllegalStateException: The application Lookup instance is not found in VaadinContext. The instance is supposed to be created by a ServletContainerInitializer. Issues known to cause this problem are:

- A Spring Boot application deployed as a war-file but the main application class does not extend SpringBootServletInitializer

- An embedded server that is not set up to execute ServletContainerInitializers

- Unit tests which do not properly set up the context for the test...........

In our case, the issue was resolved by excluding Hilla from the vaadin-spring-boot-starter dependency, like this:

<dependency>
  <groupId>com.vaadin</groupId>
  <artifactId>vaadin-spring-boot-starter</artifactId>
  <exclusions>
    <exclusion>
      <groupId>com.vaadin</groupId>
      <artifactId>hilla</artifactId>
    </exclusion>
  </exclusions>
</dependency>

Thank you for the update.
This is still weird because, based on the error, it looks like the embedded servlet container is starting processing requests before the ServletContainerInitializers are executed.
Excluding Hilla, makes it so that com.vaadin.hilla.route.RouteUtil.isRouteAllowed is not invoked, but most likely the issue remains, but not hit.

It would be nice to put a break point into LookupServletContainerInitializer to understand if it is effectively called later.

Hi Marco, I have used breakpoints on my localhost to see where each of those calls get called. During startup they are called and then occasionally during normal navigation. But we do not see this stack trace when running on localhost. We only see it on our k8s cluster deployment.

I am not able to put a breakpoint on our k8s servers, so I cannot see if it is still called and now finding the Lookup.class.
It is strange that a project that is not using Hilla, has to exclude Hilla to stop stack traces.

Try permitAll() for /actuator/health or whatever health endpoint you have configured - your container needs to access this endpoint during pod startup in order to check the liveliness of your pod.

That’s probably why it is working locally but not in k8s.

EDIT: I didn’t mean to reply to Marco. This was for Andre G Developer obviously. :slight_smile:

2 Likes

I will also note that without this specific Hilla exclusion, the stack trace logs do not stop occurring after the app has started up and the app is fully functioning correctly.

The log stack trace entries are being produced twice at the same time every 10 seconds forever.

OK, I was just discussing this with my colleagues as well. The logs are being produced every 10 seconds, and our liveness probe is 30 seconds delay with 120 seconds period, and then readiness probe is 10 delay with 1 second period.

But, we will try what you suggested, it makes sense that the probes are allowed through.

Because your container fails to start your pod - it needs access to your health endpoint.
You should see errors in the pod event tab as well.
We had the same issue and we had to add permitAll() for our health endpoint. That solved it.

see my (misplaced) answer to Marco above.

1 Like

@torsten.welches Hi Torsten, we added /actuator/health to our permitAll, as this was needed, but it did not stop the logging problem.

K8s was always reporting a healthy app and not complaining about the liveness probe on the actuator endpoint.

For now, we continue with the Hilla exclusion and I marked it as the solution, until we can think of or find a better way to stop the logging.

Thanks @torsten.welches @marcoc_753