spring-projects/spring-boot · error · GradleException
Each image building cache can be configured only once
Error message
Each image building cache can be configured only once
What it means
Thrown by CacheSpec.volume when this.cache is already non-null, meaning a cache configuration method (volume, bind, or image) has already been called on this CacheSpec. Each CacheSpec can configure exactly one cache type; calling a second method throws. This is the volume() entry point — the first of the three mutually exclusive cache configurators.
Solutions
- Keep only one cache configuration block (volume, bind, or image) per CacheSpec in your bootBuildImage configuration.
- Audit the build script for duplicate cache { volume/bind/image } calls and remove all but one.
- If you need different caches for different purposes, they must be on separate CacheSpec instances (e.g. different builder phases), not the same one.
Example fix
// before
tasks.bootBuildImage {
cache {
volume { name = "my-cache" }
bind { source = "/tmp/cache" } // throws
}
}
// after
tasks.bootBuildImage {
cache {
bind { source = "/tmp/cache" }
}
} Defensive patterns
Strategy: validation
Validate before calling
// Track cache configuration count in your build script and assert uniqueness.
def cacheTypes = []
tasks.bootBuildImage {
cache {
// only call ONE of: volume {}, bind {}, image {}
if (cacheTypes) throw new GradleException("Cache already configured: " + cacheTypes)
cacheTypes << 'volume'
volume { name = "my-cache" }
}
} Prevention
- Configure exactly one cache type per CacheSpec (volume, bind, or image).
- Audit build scripts after refactoring cache configuration.
- When migrating cache types, remove the old block before adding the new one.
When it happens
Trigger: Calling cache.volume { } after already calling cache.volume { }, cache.bind { }, or cache.image { } on the same CacheSpec instance within a bootBuildImage task configuration block.
Common situations: Copy-pasting DSL blocks that each configure a different cache type. Migrating from a volume cache to a bind cache and forgetting to remove the old block. Misunderstanding that only one cache type is allowed per CacheSpec.
Related errors
- Each image building cache can be configured only once
- Invalid Docker configuration, either context or host can be…
- Invalid Docker registry configuration, either token or…
- Invalid value for option '--environment'. Expected…
- Could not save the project, the server did not set a…
AI-assisted analysis of spring-projects/spring-boot@270dfe353f (2026-08-11).
Data as JSON: /api/errors/fadfe1925ed17157.
Report an issue: GitHub.
Appendix: source
Thrown at build-plugin/spring-boot-gradle-plugin/src/main/java/org/springframework/boot/gradle/tasks/bundling/CacheSpec.java:59
private @Nullable Cache cache;
@Inject
public CacheSpec(ObjectFactory objectFactory) {
this.objectFactory = objectFactory;
}
public @Nullable Cache asCache() {
return this.cache;
}
/**
* Configures a volume cache using the given {@code action}.
* @param action the action
*/
public void volume(Action<VolumeCacheSpec> action) {
if (this.cache != null) {
throw new GradleException("Each image building cache can be configured only once");
}
VolumeCacheSpec spec = this.objectFactory.newInstance(VolumeCacheSpec.class);
action.execute(spec);
this.cache = Cache.volume(spec.getName().get());
}
/**
* Configures a bind cache using the given {@code action}.
* @param action the action
*/
public void bind(Action<BindCacheSpec> action) {
if (this.cache != null) {
throw new GradleException("Each image building cache can be configured only once");
}
BindCacheSpec spec = this.objectFactory.newInstance(BindCacheSpec.class);
action.execute(spec);
this.cache = Cache.bind(spec.getSource().get());
}View on GitHub (pinned to 270dfe353f)