Spring Boot
NoSuchMethodError
ServletContext
Spring MVC
Java

Getting NoSuchMethodError javax.servlet.ServletContext.addServlet in Spring Boot while running a Spring MVC application

Master System Design with Codemia

Enhance your system design skills with over 120 practice problems, detailed solutions, and hands-on exercises.

Introduction

NoSuchMethodError: javax.servlet.ServletContext.addServlet in Spring Boot means there is a servlet API version conflict on the classpath. Spring Boot's embedded Tomcat requires Servlet API 3.1+ (for Spring Boot 2.x) or Jakarta Servlet 6.0+ (for Spring Boot 3.x). This error occurs when an older servlet API jar (2.5 or 3.0) is pulled in as a transitive dependency and takes precedence over the correct version. The fix is to exclude the conflicting dependency.

The Error

 
java.lang.NoSuchMethodError: javax.servlet.ServletContext.addServlet(
    Ljava/lang/String;Ljavax/servlet/Servlet;)Ljavax/servlet/ServletRegistration$Dynamic;

Or in Spring Boot 3.x:

 
java.lang.NoSuchMethodError: jakarta.servlet.ServletContext.addServlet

The addServlet method was added in Servlet 3.0. If an older servlet API is loaded first, the method does not exist.

Fix 1: Find and Exclude the Conflicting Dependency

Maven

bash
1# Find which dependency brings in the old servlet API
2mvn dependency:tree -Dincludes=javax.servlet
3
4# Example output:
5# [INFO] +- com.example:legacy-lib:jar:1.0
6# [INFO] |  \- javax.servlet:servlet-api:jar:2.5:compile  ← Problem!

Exclude it:

xml
1<dependency>
2    <groupId>com.example</groupId>
3    <artifactId>legacy-lib</artifactId>
4    <version>1.0</version>
5    <exclusions>
6        <exclusion>
7            <groupId>javax.servlet</groupId>
8            <artifactId>servlet-api</artifactId>
9        </exclusion>
10    </exclusions>
11</dependency>

Gradle

bash
# Find the conflict
gradle dependencies --configuration compileClasspath | grep servlet
groovy
1implementation('com.example:legacy-lib:1.0') {
2    exclude group: 'javax.servlet', module: 'servlet-api'
3}
4
5// Or globally exclude the old API
6configurations.all {
7    exclude group: 'javax.servlet', module: 'servlet-api'
8}

Fix 2: Ensure the Correct Servlet API Version

For Spring Boot 2.x:

xml
1<!-- Spring Boot's starter-web provides the correct servlet API -->
2<dependency>
3    <groupId>org.springframework.boot</groupId>
4    <artifactId>spring-boot-starter-web</artifactId>
5</dependency>
6
7<!-- Do NOT add these manually — they conflict -->
8<!-- javax.servlet:servlet-api:2.5 ← WRONG -->
9<!-- javax.servlet:javax.servlet-api:3.0.1 ← May conflict -->

For Spring Boot 3.x (Jakarta EE 9+):

xml
1<dependency>
2    <groupId>org.springframework.boot</groupId>
3    <artifactId>spring-boot-starter-web</artifactId>
4</dependency>
5
6<!-- Spring Boot 3 uses jakarta.servlet, not javax.servlet -->
7<!-- Any javax.servlet dependency on the classpath causes conflicts -->

Fix 3: Set the Correct scope for servlet-api

If you must declare the servlet API explicitly, mark it as provided:

xml
1<!-- For external Tomcat deployment -->
2<dependency>
3    <groupId>javax.servlet</groupId>
4    <artifactId>javax.servlet-api</artifactId>
5    <version>4.0.1</version>
6    <scope>provided</scope>
7</dependency>
8
9<!-- Spring Boot 3.x -->
10<dependency>
11    <groupId>jakarta.servlet</groupId>
12    <artifactId>jakarta.servlet-api</artifactId>
13    <version>6.0.0</version>
14    <scope>provided</scope>
15</dependency>

provided scope means the dependency is available at compile time but not packaged — the embedded Tomcat provides it at runtime.

Diagnosing the Classpath Conflict

java
1// Add this to your main method temporarily to find which jar provides ServletContext
2import javax.servlet.ServletContext;
3
4System.out.println(ServletContext.class.getProtectionDomain()
5    .getCodeSource().getLocation());
6// Should print something like:
7// .../tomcat-embed-core-9.0.x.jar (correct)
8// .../servlet-api-2.5.jar (WRONG — old version)
bash
# List all jars containing ServletContext
find ~/.m2/repository -name "*.jar" -exec sh -c 'jar -tf {} | grep -q "ServletContext.class" && echo {}' \;

Spring Boot 3.x Migration (javax to jakarta)

Spring Boot 3.x moved from javax.servlet to jakarta.servlet:

java
1// Spring Boot 2.x
2import javax.servlet.http.HttpServletRequest;
3
4// Spring Boot 3.x
5import jakarta.servlet.http.HttpServletRequest;

If you see the error after upgrading to Spring Boot 3.x, check for leftover javax.servlet imports and dependencies:

bash
# Find javax.servlet references in your code
grep -r "javax.servlet" src/

Common Pitfalls

  • Manually adding servlet-api to the POM: Spring Boot's spring-boot-starter-web includes the correct servlet API via tomcat-embed-core. Manually adding javax.servlet:servlet-api creates a conflict. Remove the explicit dependency and let Spring Boot manage it.
  • Legacy libraries bundling old servlet API: Libraries written for older Java EE versions often declare javax.servlet:servlet-api:2.5 as a compile dependency. Always check mvn dependency:tree and exclude these transitive dependencies.
  • Running on an external Tomcat with wrong version: If deploying to an external Tomcat instead of the embedded one, the Tomcat version must match Spring Boot's requirements. Spring Boot 2.x needs Tomcat 9+; Spring Boot 3.x needs Tomcat 10+.
  • Mixing Spring Boot 3.x with javax dependencies: Spring Boot 3.x uses Jakarta EE 9+ (jakarta namespace). Any library that depends on javax.servlet causes conflicts. Either upgrade the library or use Spring Boot 2.x.
  • IDE caching stale classpath: After fixing the POM, IDEs may still use cached jars. Run mvn clean and reimport the project in your IDE (Maven > Reload Project in IntelliJ).

Summary

  • The error means an old servlet API jar (2.5 or 3.0) is on the classpath
  • Find the conflict with mvn dependency:tree -Dincludes=javax.servlet
  • Exclude the old servlet-api from the offending transitive dependency
  • Do not manually add servlet API dependencies — Spring Boot's starter includes the correct version
  • Spring Boot 3.x uses jakarta.servlet, not javax.servlet — update all imports after migration
  • After fixing the POM, clean the build and reimport in your IDE

Course illustration
Course illustration

All Rights Reserved.