Summary
Running the tools jarmode extract command against an executable Spring Boot WAR fails with IllegalStateException: Invalid library location WEB-INF/lib-provided/.... The extractor assumes every entry listed in WEB-INF/classpath.idx lives under the single Spring-Boot-Lib directory (WEB-INF/lib/), but an executable WAR legitimately also places the provided / embedded-container dependencies under WEB-INF/lib-provided/ and records them in the classpath index. The first lib-provided entry encountered aborts the command.
Environment
- Spring Boot: 4.1.0
- Packaging: WAR (executable,
WarLauncher)
- Java (runtime): 25
- Build: Maven WAR Plugin 3.5.1
Steps to reproduce
A minimal project generated from start.spring.io reproduces the problem.
The key factors are WAR packaging plus the web dependency, which places the embedded Tomcat and spring-boot-web-server artifacts in WEB-INF/lib-provided/.
-
Generate a project (Maven, Java, WAR packaging, Java 25, Spring Boot 4.1.0,
web dependency):
https://start.spring.io/#!type=maven-project&language=java&platformVersion=4.1.0&packaging=war&configurationFileFormat=properties&jvmVersion=25&groupId=com.example&artifactId=demo&packageName=com.example.demo&dependencies=web
-
Build the WAR: ./mvnw package
-
Run the tools jarmode extract command: java -Djarmode=tools -jar target/demo-0.0.1-SNAPSHOT.war extract
The command fails with the stack trace shown below.
Actual behavior
java.lang.IllegalStateException: java.lang.IllegalStateException: Invalid library location WEB-INF/lib-provided/spring-boot-web-server-4.1.0.jar
at org.springframework.boot.jarmode.tools.ToolsJarMode.run(ToolsJarMode.java:58)
at org.springframework.boot.loader.launch.JarModeRunner.runJarMode(JarModeRunner.java:64)
at org.springframework.boot.loader.launch.JarModeRunner.main(JarModeRunner.java:44)
...
Caused by: java.lang.IllegalStateException: Invalid library location WEB-INF/lib-provided/spring-boot-web-server-4.1.0.jar
at org.springframework.util.Assert.state(Assert.java:102)
at org.springframework.boot.jarmode.tools.IndexedJarStructure.toStructureDependency(IndexedJarStructure.java:133)
at org.springframework.boot.jarmode.tools.IndexedJarStructure.resolve(IndexedJarStructure.java:102)
at org.springframework.boot.jarmode.tools.JarStructure.resolve(JarStructure.java:40)
at org.springframework.boot.jarmode.tools.ExtractCommand.lambda$extractLibraries$0(ExtractCommand.java:162)
...
Expected behavior
extract completes and lays out the archive contents, treating WEB-INF/lib-provided/ entries as libraries (or otherwise handling them) instead of asserting on the Spring-Boot-Lib prefix.
Analysis
The WAR is internally consistent. Manifest, WEB-INF/layers.idx, and WEB-INF/classpath.idx all agree that WEB-INF/lib-provided/ exists and is on the runtime classpath. Relevant manifest attributes:
Spring-Boot-Version: 4.1.0
Spring-Boot-Lib: WEB-INF/lib/
Spring-Boot-Classpath-Index: WEB-INF/classpath.idx
Spring-Boot-Layers-Index: WEB-INF/layers.idx
Main-Class: org.springframework.boot.loader.launch.WarLauncher
During extraction, IndexedJarStructure.resolve(String) classifies every archive entry.
Any entry present in classpathEntries (loaded verbatim from classpath.idx) is treated as a library and passed to toStructureDependency, which asserts on the Spring-Boot-Lib prefix:
private String toStructureDependency(String location) {
Assert.state(location.startsWith(this.libLocation), // libLocation = "WEB-INF/lib/"
() -> "Invalid library location " + location);
return location.substring(this.libLocation.length());
}
Our context
We are transitioning from traditional WAR deployments to running Spring Boot applications with the embedded Tomcat. During this transition we need to keep producing WAR files, while still using the tools jarmode to build layered container images. Hence, we would welcome a fix that allows tools extract to work with executable WARs as well.
Summary
Running the
toolsjarmodeextractcommand against an executable Spring Boot WAR fails withIllegalStateException: Invalid library location WEB-INF/lib-provided/.... The extractor assumes every entry listed inWEB-INF/classpath.idxlives under the singleSpring-Boot-Libdirectory (WEB-INF/lib/), but an executable WAR legitimately also places the provided / embedded-container dependencies underWEB-INF/lib-provided/and records them in the classpath index. The firstlib-providedentry encountered aborts the command.Environment
WarLauncher)Steps to reproduce
A minimal project generated from start.spring.io reproduces the problem.
The key factors are WAR packaging plus the
webdependency, which places the embedded Tomcat andspring-boot-web-serverartifacts inWEB-INF/lib-provided/.Generate a project (Maven, Java, WAR packaging, Java 25, Spring Boot 4.1.0,
webdependency):https://start.spring.io/#!type=maven-project&language=java&platformVersion=4.1.0&packaging=war&configurationFileFormat=properties&jvmVersion=25&groupId=com.example&artifactId=demo&packageName=com.example.demo&dependencies=web
Build the WAR:
./mvnw packageRun the
toolsjarmodeextractcommand:java -Djarmode=tools -jar target/demo-0.0.1-SNAPSHOT.war extractThe command fails with the stack trace shown below.
Actual behavior
Expected behavior
extractcompletes and lays out the archive contents, treatingWEB-INF/lib-provided/entries as libraries (or otherwise handling them) instead of asserting on theSpring-Boot-Libprefix.Analysis
The WAR is internally consistent. Manifest,
WEB-INF/layers.idx, andWEB-INF/classpath.idxall agree thatWEB-INF/lib-provided/exists and is on the runtime classpath. Relevant manifest attributes:During extraction,
IndexedJarStructure.resolve(String)classifies every archive entry.Any entry present in
classpathEntries(loaded verbatim fromclasspath.idx) is treated as a library and passed totoStructureDependency, which asserts on theSpring-Boot-Libprefix:Our context
We are transitioning from traditional WAR deployments to running Spring Boot applications with the embedded Tomcat. During this transition we need to keep producing WAR files, while still using the
toolsjarmode to build layered container images. Hence, we would welcome a fix that allowstools extractto work with executable WARs as well.