spring-projects/spring-boot · error · IllegalStateException
Failed to load layers configuration with name
Error message
Failed to load layers configuration with name '%s': '%s' not found
What it means
Thrown by AbstractPackagerMojo.loadLayersConfigurationFromClasspath when the plugin's class realm cannot resolve the resource META-INF/spring/layers/<configurationName>.xml. The layers feature lets you split a fat jar into layers for better Docker caching; a named configuration must exist as a classpath resource at that exact location. A null InputStream means the resource is absent from every JAR/plugin dependency the realm can see.
Solutions
- Verify the exact resource path: the file must live at META-INF/spring/layers/<configurationName>.xml inside a JAR that the maven plugin can load (a plugin dependency, not just the application classpath).
- Correct the <configurationName> value to match the filename (without .xml) of an existing layers.xml.
- If using a custom layers file, bundle it in a dependency JAR listed under <plugin><dependencies> for spring-boot-maven-plugin, or drop the configurationName to fall back to IMPLICIT_LAYERS.
- Rebuild the artifact that is supposed to carry the resource and confirm with `jar tf <artifact>.jar | grep 'META-INF/spring/layers'` that the file is actually packaged.
Example fix
// before: <layers><configurationName>cunstom</configurationName></layers> // after: <layers><configurationName>custom</configurationName></layers> // matches META-INF/spring/layers/custom.xml
Defensive patterns
Strategy: validation
Validate before calling
// Before configuring <layers><configurationName>NAME</configurationName></layers>:
String name = /* configured value */;
String loc = "META-INF/spring/layers/" + name + ".xml";
try (var in = Thread.currentThread().getContextClassLoader().getResourceAsStream(loc)) {
if (in == null) {
throw new IllegalStateException("Missing layers resource: " + loc
+ " — verify the file ships in a plugin dependency the realm can see.");
}
} Try / catch
// In a build-extension wrapper around the plugin goal:
try {
// invoke repackage/build-image
} catch (IllegalStateException ex) {
if (ex.getMessage().startsWith("Failed to load layers configuration")) {
// surface a hint pointing at META-INF/spring/layers/<name>.xml
}
throw ex;
} Prevention
- Keep the layers.xml filename and <configurationName> in sync via a single property.
- Run `jar tf <plugin-dep>.jar | grep META-INF/spring/layers` in CI to assert the resource exists.
- Omit <configurationName> when the default IMPLICIT_LAYERS is acceptable.
When it happens
Trigger: Setting <layers><configurationName>foo</configurationName></layers> in the plugin config when no META-INF/spring/layers/foo.xml is present on the plugin descriptor's class realm (getResourceAsStream returns null). Triggered during repackage/build-image when layers are enabled and a configurationName is supplied.
Common situations: Typo in configurationName; resource shipped in the application JAR instead of a plugin dependency the realm sees; resource placed under src/main/resources of the app rather than the plugin; upgrading Spring Boot and the legacy layers.xml path moved; custom layer config only declared but never added to the build classpath.
Related errors
- Unable to load layers XSD
- Could not build classpath
- Failed to generate build-info.properties.
- Failed to process custom layers configuration
- Invalid Docker configuration, either context or host can be…
AI-assisted analysis of spring-projects/spring-boot@270dfe353f (2026-08-11).
Data as JSON: /api/errors/8e0f1e1f8f603718.
Report an issue: GitHub.
Appendix: source
Thrown at build-plugin/spring-boot-maven-plugin/src/main/java/org/springframework/boot/maven/AbstractPackagerMojo.java:215
}
private org.springframework.boot.loader.tools.Layers loadLayersConfiguration() {
File configuration = this.layers.getConfiguration();
if (configuration != null) {
return getCustomLayers(configuration.getAbsolutePath(), () -> new FileInputStream(configuration));
}
String configurationName = this.layers.getConfigurationName();
if (configurationName != null) {
String location = "META-INF/spring/layers/%s.xml".formatted(configurationName);
return getCustomLayers(location, () -> loadLayersConfigurationFromClasspath(configurationName, location));
}
return IMPLICIT_LAYERS;
}
private InputStream loadLayersConfigurationFromClasspath(String name, String location) {
InputStream in = this.pluginDescriptor.getClassRealm().getResourceAsStream(location);
if (in == null) {
throw new IllegalStateException(
"Failed to load layers configuration with name '%s': '%s' not found".formatted(name, location));
}
return in;
}
private CustomLayers getCustomLayers(String source, InputStreamSource inputStreamSource) {
try {
Document document = getDocumentIfAvailable(inputStreamSource);
return new CustomLayersProvider().getLayers(document);
}
catch (Exception ex) {
throw new IllegalStateException("Failed to process custom layers configuration " + source, ex);
}
}
private Document getDocumentIfAvailable(InputStreamSource source) throws Exception {
try (InputStream in = source.getInputStream()) {
InputSource inputSource = new InputSource(in);View on GitHub (pinned to 270dfe353f)