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 LocalCacheSpec.volume when this.cache is already non-null. LocalCacheSpec is the local-cache counterpart to CacheSpec (which also supports image caches). Each LocalCacheSpec accepts exactly one cache configuration: either volume or bind. Calling volume() a second time, or calling it after bind(), throws.

Solutions

  1. Keep exactly one cache configuration (volume or bind) per LocalCacheSpec.
  2. Audit the build script for multiple cache { } sub-blocks and remove duplicates.

Example fix

// before
cache {
    volume { name = "vol" }
    bind { source = "/tmp/cache" }  // throws
}
// after
cache {
    volume { name = "vol" }
}
Defensive patterns

Strategy: validation

Validate before calling

// Ensure no prior cache is configured before calling volume().
if (localCacheSpec.asCache() != null) {
    throw new GradleException("Local cache already configured; cannot call volume().")
}

Prevention

When it happens

Trigger: Calling cache.volume { } after already calling cache.volume { } or cache.bind { } on the same LocalCacheSpec instance in a bootBuildImage (or related) configuration.

Common situations: Duplicate cache blocks in the build script. Refactoring from one cache type to another without removing the old block. Misunderstanding that LocalCacheSpec supports only one cache.

Related errors


AI-assisted analysis of spring-projects/spring-boot@270dfe353f (2026-08-11). Data as JSON: /api/errors/6dbbda490bca7d0a. Report an issue: GitHub.

Appendix: source

Thrown at build-plugin/spring-boot-gradle-plugin/src/main/java/org/springframework/boot/gradle/tasks/bundling/LocalCacheSpec.java:59

	private @Nullable LocalCache cache;

	@Inject
	public LocalCacheSpec(ObjectFactory objectFactory) {
		this.objectFactory = objectFactory;
	}

	public @Nullable LocalCache 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)