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 the build cache has already been configured (this.cache != null). A CacheSpec models a single cache; volume/bind/image are mutually exclusive and each can be set at most once. Raised as GradleException.

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 5b2dbdbb8b)

Solutions

  1. Configure the build cache exactly once with a single call: buildCache { volume { name = 'my-cache' } }.
  2. Remove duplicate buildCache {} blocks contributed by other applied scripts/plugins.
  3. If you need to switch cache type, delete the previous block first — do not stack them.
  4. Search the build for 'buildCache'/'volume {' to find all contributors.

Example fix

// before: cache configured twice
bootBuildImage {
    buildCache { volume { name = 'cache-a' } }
    buildCache { volume { name = 'cache-b' } } // throws
}
// after: single configuration
bootBuildImage {
    buildCache { volume { name = 'cache-a' } }
}
Defensive patterns

Strategy: validation

Validate before calling

// Track cache configuration count to prevent double-config
var cacheConfigured = false
fun configureVolume(name: String) {
    check(!cacheConfigured) { "Build cache already configured" }
    cacheConfigured = true
    // ... buildCache { volume { this.name = name } }
}

Prevention

When it happens

Trigger: Calling buildCache { volume { } } twice, or calling buildCache { volume {...} } after buildCache { bind {...} } (or image {...}) — the second call sees this.cache already set and throws at line 59.

Common situations: Copy-pasting cache config blocks; a shared plugin/Convention applying cache config that the build script also sets; migrating from volume to bind cache without removing the old block.

Related errors


AI-assisted analysis of spring-projects/spring-boot@5b2dbdbb8b (2026-08-04). Data as JSON: /data/errors/fadfe1925ed17157.json. Report an issue: GitHub.