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

I get the same issue when running spring actuator on a DIFFERENT port, i.e., server.port and management.server.port are different. The issue does not occur when the ports are the same.

(Note that using a different port creates a second embedded web server instance.)

The app runs fine, as the stack trace is only triggered when the actuator url is called. Using flow instead of Hilla. Latest version of Vaadin.

Needless to say, management.security.enabled=false does NOT bypass the VaadinWebSecurity class :-) So you also need an entry in your SecurityConfig just to make the url available.

I don’t yet have a solution. I can ping the management url in the browser and get a result, but the vaadin app still logs the stack trace. I am still having trouble getting prometheus to work, though.

The stack trace log occurs whether or not your application inherits from SpringBootServletInitializer.

Correction: Turning off spring security entirely (anyRequest().permitAll()) makes everything work. Prometheus is happy, calling the management url from the browser works, and no stack trace.

Hard to say what your real problem is without seeing your security configuration. Might just be a missing actuator security configuration

Or just a bad one :-) Here is a working solution for spring actuator using an optional second port.

import org.jspecify.annotations.Nullable;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.env.Environment;
import org.springframework.http.HttpMethod;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.web.servlet.util.matcher.PathPatternRequestMatcher;
import org.springframework.security.web.util.matcher.AndRequestMatcher;
import org.springframework.security.web.util.matcher.RequestMatcher;
import com.vaadin.flow.spring.security.VaadinWebSecurity;

@EnableWebSecurity
@Configuration
public class SecurityConfigWithManagement extends VaadinWebSecurity {

	private final @Nullable RequestMatcher managementPortMatcher;

	public SecurityConfigWithManagement(Environment env) {
		int serverPort = env.getProperty("server.port", Integer.class);
		int managementPort = env.getProperty("management.server.port", Integer.class, serverPort);
		managementPortMatcher = serverPort == managementPort ? null : forPortAndPath(managementPort, HttpMethod.GET, "/actuator/**");
	}

	@Override
	protected void configure(HttpSecurity http) throws Exception {
		if (managementPortMatcher != null) {
			http.authorizeHttpRequests(authorize -> authorize.requestMatchers(managementPortMatcher).permitAll());
		}
		super.configure(http);
	}

	private static RequestMatcher forPortAndPath(int port, HttpMethod method, String pathPattern) {
		RequestMatcher portMatcher = forPort(port);
		PathPatternRequestMatcher pathMatcher = PathPatternRequestMatcher.withDefaults().matcher(method, pathPattern);
		return new AndRequestMatcher(portMatcher, pathMatcher);
	}

	private static RequestMatcher forPort(int port) {
		return request -> port == request.getLocalPort();
	}
}