The mystery of failed deployment in Tomcat 10

Hi! I am trying to deploy apps made with vaadin 24.9 and JDK 21 to Tomcat 10.1 running on a laptop, but nothing seems to work. All the apps run nicely in IntelliJ, but I get the same error message from Tomcat when I try to start the app packaged as a war-file. What am I doing wrong here?

I have followed the instructions shown here: https://foojay.io/today/how-to-deploy-a-vaadin-application-as-a-war-on-tomcat-11/,. The war file is packaged with mvn clean package -Pproduction, the war file moved to webapps folder, changed owner to tomcat:tomcat, and the file is unzipped by Tomcat. The app name appears in the Manager. When I try to start the app in the Manager, nothing happens. The localhost log from tomcat shows this:

05-Oct-2025 07:42:50.175 INFO [http-nio-8080-exec-95] org.apache.catalina.core.ApplicationContext.log 1 Spring WebApplicationInitializers detected on classpath
05-Oct-2025 07:42:50.180 SEVERE [http-nio-8080-exec-95] org.apache.catalina.core.StandardContext.listenerStart Exception sending context initialized event to listener instance of class [com.vaadin.flow.server.startup.ServletContextListeners]
        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.flow.server.startup.ServletDeployer.contextInitialized(ServletDeployer.java:152)
                at com.vaadin.flow.server.startup.ServletContextListeners.contextInitialized(ServletContextListeners.java:44)
                at org.apache.catalina.core.StandardContext.listenerStart(StandardContext.java:4046)
                at org.apache.catalina.core.StandardContext.startInternal(StandardContext.java:4474)
                at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:164)
                at org.apache.catalina.manager.ManagerServlet.start(ManagerServlet.java:1289)
                at org.apache.catalina.manager.HTMLManagerServlet.start(HTMLManagerServlet.java:644)
                at org.apache.catalina.manager.HTMLManagerServlet.doPost(HTMLManagerServlet.java:190)
                at jakarta.servlet.http.HttpServlet.service(HttpServlet.java:590)
                at jakarta.servlet.http.HttpServlet.service(HttpServlet.java:658)
                at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:195)
                at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:140)
                at org.apache.catalina.filters.CsrfPreventionFilter.doFilter(CsrfPreventionFilter.java:430)
                at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:164)
                at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:140)
                at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:51)
                at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:164)
                at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:140)
                at org.apache.catalina.filters.HttpHeaderSecurityFilter.doFilter(HttpHeaderSecurityFilter.java:129)
                at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:164)
                at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:140)
                at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:167)
                at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:90)
                at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:598)
                at org.apache.catalina.valves.RequestFilterValve.process(RequestFilterValve.java:354)
                at org.apache.catalina.valves.RemoteAddrValve.invoke(RemoteAddrValve.java:54)
                at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:116)
                at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:93)
                at org.apache.catalina.valves.AbstractAccessLogValve.invoke(AbstractAccessLogValve.java:666)
                at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:74)
                at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:344)
                at org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:398)
                at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:63)
                at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:903)
                at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1776)
                at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:52)
                at org.apache.tomcat.util.threads.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:975)
                at org.apache.tomcat.util.threads.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:493)
                at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:63)
                at java.base/java.lang.Thread.run(Thread.java:840)

It claims that I haven’t extended SpringBootServletInitializer, but I mean I have, in Application.class:

package com.example;

import com.vaadin.flow.component.page.AppShellConfigurator;
import com.vaadin.flow.theme.Theme;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.builder.SpringApplicationBuilder;
import org.springframework.boot.web.servlet.support.SpringBootServletInitializer;

@SpringBootApplication
@Theme("default")
public class Application extends SpringBootServletInitializer implements AppShellConfigurator {

    @Override
    protected SpringApplicationBuilder configure(SpringApplicationBuilder application) {
        return application.sources(Application.class);
    }

    public static void main(String[] args) {
        SpringApplication.run(Application.class, args);
    }

}

The same thing happens with vaadin apps created with Vaadin starter in IntelliJ.
The pom file is as follows:

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <!-- Project from https://start.vaadin.com/0e1afa6f-40c8-42c9-93d6-178caed93bdd -->
    <groupId>com.example</groupId>
    <artifactId>app</artifactId>
    <version>1.0-SNAPSHOT</version>
    <packaging>war</packaging>

    <properties>
        <java.version>21</java.version>
        <vaadin.version>24.9.2</vaadin.version>
    </properties>

    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>3.5.6</version>
        <relativePath/>
    </parent>


    <dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>com.vaadin</groupId>
                <artifactId>vaadin-bom</artifactId>
                <version>${vaadin.version}</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
        </dependencies>
    </dependencyManagement>

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-tomcat</artifactId>
            <scope>provided</scope>
        </dependency>

        <dependency>
            <groupId>com.vaadin</groupId>
            <!-- Replace artifactId with vaadin-core to use only free components -->
            <artifactId>vaadin</artifactId>
        </dependency>

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

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-jpa</artifactId>
        </dependency>
        <dependency>
            <groupId>com.h2database</groupId>
            <artifactId>h2</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
    </dependencies>

    <build>
        <defaultGoal>spring-boot:run</defaultGoal>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
            <plugin>
                <groupId>com.vaadin</groupId>
                <artifactId>vaadin-maven-plugin</artifactId>
                <version>${vaadin.version}</version>
                <executions>
                    <execution>
                        <goals>
                            <goal>prepare-frontend</goal>
                        </goals>
                    </execution>
                </executions>
            </plugin>
        </plugins>
    </build>

    <profiles>
        <profile>
            <id>production</id>
            <dependencies>
                <dependency>
                    <!-- Exclude development dependencies from production -->
                    <groupId>com.vaadin</groupId>
                    <artifactId>vaadin-core</artifactId>
                    <exclusions>
                        <exclusion>
                            <groupId>com.vaadin</groupId>
                            <artifactId>vaadin-dev</artifactId>
                        </exclusion>
                    </exclusions>
                </dependency>
            </dependencies>
            <build>
                <plugins>
                    <plugin>
                        <groupId>com.vaadin</groupId>
                        <artifactId>vaadin-maven-plugin</artifactId>
                        <version>${vaadin.version}</version>
                        <executions>
                            <execution>
                                <goals>
                                    <goal>build-frontend</goal>
                                </goals>
                                <phase>compile</phase>
                            </execution>
                        </executions>
                    </plugin>
                </plugins>
            </build>
        </profile>
    </profiles>

    <repositories>
        <repository>
            <id>vaadin-directory</id>
            <url>https://maven.vaadin.com/vaadin-addons</url>
        </repository>
        <repository>
            <id>vaadin-prereleases</id>
            <url>https://maven.vaadin.com/vaadin-prereleases</url>
        </repository>
    </repositories>
    <pluginRepositories>
        <pluginRepository>
            <id>vaadin-prereleases</id>
            <url>https://maven.vaadin.com/vaadin-prereleases</url>
        </pluginRepository>
    </pluginRepositories>
</project>

I have tried removing the AppShellConfigurator implementation, but it doesn’t help.

I just tried the same steps, and the application deployed correctly on Tomcat 10.1.44.
What I did:

  • Create a new Vaadin project from IntelliJ IDEA
  • Apply the changes explained in the linked blog post (also double checked with Traditional Deployment :: Spring Boot)
  • Copy the WAR file in the Tomcat webapp folder.
1 Like

Thanks for the reply, Marco. There must be something wrong with my setup, then. I develop on Debian 12, and have used both Debian 12 and 13 on the server running Tomcat . All linux distros updated to last version. How about you - and what flavour of Java do you use?

I don’t think it is a matter of OS.
I would instead double-check the Tomcat installation. Which exact version? Did you download Tomcat and install it manually, or are you using an installation provided by the distro? Are there any custom configurations applied?

I tested locally with Tomcat 10.1.44 installed with SDKMAN (basically like downloading the zip and unpacking it) on an Ubuntu 24.04, running it with Temurin 21.0.6.

1 Like

The version of Tomcat is 10.1.40.0, installed using apt. Plain vanilla, no custom configuration. I downloaded JDKMAN, and installed JDK Temurin 21.0.8 (21.0.6 was not in the SDKMAN repo) both on both machines. Packaged for production again (maven clean package -Pproduction), copied war-file to /var/lib/tomcat10/webapps, and it appeared in Tomcat Manager. But still did not start. This the status of tomcat using systemctl:

hallvard@debian-hjemmeserver:~/Tomcatapps$ sudo systemctl status tomcat10
â—Ź tomcat10.service - Apache Tomcat 10 Web Application Server
     Loaded: loaded (/lib/systemd/system/tomcat10.service; enabled; preset: enabled)
     Active: active (running) since Mon 2025-10-06 18:38:47 CEST; 23min ago
       Docs: https://tomcat.apache.org/tomcat-10.0-doc/index.html
    Process: 734 ExecStartPre=/usr/libexec/tomcat10/tomcat-update-policy.sh (code=exited, status=0/SUCCESS)
   Main PID: 784 (java)
      Tasks: 39 (limit: 9272)
     Memory: 866.6M
        CPU: 1min 41.315s
     CGroup: /system.slice/tomcat10.service
             └─784 /usr/lib/jvm/default-java/bin/java -Djava.util.logging.config.file=/var/lib/tomcat10/conf/logging.properties -Djava.util.logging.manager=org.apache.juli.ClassLoaderLogManager -Djava.awt.headless=>

okt. 06 18:50:57 debian-hjemmeserver tomcat10[784]:  org.apache.catalina.core.ContainerBase$ContainerBackgroundProcessor.processChildren(ContainerBase.java:1176)
okt. 06 18:50:57 debian-hjemmeserver tomcat10[784]:  org.apache.catalina.core.ContainerBase$ContainerBackgroundProcessor.processChildren(ContainerBase.java:1176)
okt. 06 18:50:57 debian-hjemmeserver tomcat10[784]:  org.apache.catalina.core.ContainerBase$ContainerBackgroundProcessor.run(ContainerBase.java:1154)
okt. 06 18:50:57 debian-hjemmeserver tomcat10[784]:  java.base@17.0.16/java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:539)
okt. 06 18:50:57 debian-hjemmeserver tomcat10[784]:  java.base@17.0.16/java.util.concurrent.FutureTask.runAndReset(FutureTask.java:305)
okt. 06 18:50:57 debian-hjemmeserver tomcat10[784]:  java.base@17.0.16/java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(ScheduledThreadPoolExecutor.java:305)
okt. 06 18:50:57 debian-hjemmeserver tomcat10[784]:  java.base@17.0.16/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1136)
okt. 06 18:50:57 debian-hjemmeserver tomcat10[784]:  java.base@17.0.16/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:635)
okt. 06 18:50:57 debian-hjemmeserver tomcat10[784]:  org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:63)
okt. 06 18:50:57 debian-hjemmeserver tomcat10[784]:  java.base@17.0.16/java.lang.Thread.run(Thread.java:840)

The tomcat10.service is as follows:

[Unit]
Description=Apache Tomcat 10 Web Application Server
Documentation=https://tomcat.apache.org/tomcat-10.0-doc/index.html
After=network.target
RequiresMountsFor=/var/log/tomcat10 /var/lib/tomcat10

[Service]

# Configuration
Environment="CATALINA_HOME=/usr/share/tomcat10"
Environment="CATALINA_BASE=/var/lib/tomcat10"
Environment="CATALINA_TMPDIR=/tmp"
Environment="JAVA_OPTS=-Djava.awt.headless=true"

# Lifecycle
Type=simple
ExecStartPre=+/usr/libexec/tomcat10/tomcat-update-policy.sh
ExecStart=/bin/sh /usr/libexec/tomcat10/tomcat-start.sh
SuccessExitStatus=143
Restart=on-abort

# Logging
SyslogIdentifier=tomcat10

# Security
User=tomcat
Group=tomcat
PrivateTmp=yes
AmbientCapabilities=CAP_NET_BIND_SERVICE
NoNewPrivileges=true
CacheDirectory=tomcat10
CacheDirectoryMode=750
ProtectSystem=strict
ReadWritePaths=/etc/tomcat10/Catalina/
ReadWritePaths=/var/lib/tomcat10/webapps/
ReadWritePaths=/var/log/tomcat10/

It seems my Tomcat 10 runs Java 17. How do I force it to use the sdkman current verison?

I’d say you have to export JAVA_HOME pointing to the correct JDK in your service file

1 Like

Thank you so much, Marco! It was the java version all along. It worked when I downloaded and installed tomcat 10.1.47 manually, and then pointed to a regularly installed jdk v21 in the tomcat.service file. Somehow the sdkman jdks (or my installation of them) was not what tomcat 10 wanted.