{"id":"6dbbda490bca7d0a","repo":"spring-projects/spring-boot","slug":"each-image-building-cache-can-be-configured-only-o-6dbbda","errorCode":null,"errorMessage":"Each image building cache can be configured only once","messagePattern":"Each image building cache can be configured only once","errorType":"validation","errorClass":"GradleException","httpStatus":null,"severity":"error","filePath":"build-plugin/spring-boot-gradle-plugin/src/main/java/org/springframework/boot/gradle/tasks/bundling/LocalCacheSpec.java","lineNumber":59,"sourceCode":"\n\tprivate @Nullable LocalCache cache;\n\n\t@Inject\n\tpublic LocalCacheSpec(ObjectFactory objectFactory) {\n\t\tthis.objectFactory = objectFactory;\n\t}\n\n\tpublic @Nullable LocalCache asCache() {\n\t\treturn this.cache;\n\t}\n\n\t/**\n\t * Configures a volume cache using the given {@code action}.\n\t * @param action the action\n\t */\n\tpublic void volume(Action<VolumeCacheSpec> action) {\n\t\tif (this.cache != null) {\n\t\t\tthrow new GradleException(\"Each image building cache can be configured only once\");\n\t\t}\n\t\tVolumeCacheSpec spec = this.objectFactory.newInstance(VolumeCacheSpec.class);\n\t\taction.execute(spec);\n\t\tthis.cache = Cache.volume(spec.getName().get());\n\t}\n\n\t/**\n\t * Configures a bind cache using the given {@code action}.\n\t * @param action the action\n\t */\n\tpublic void bind(Action<BindCacheSpec> action) {\n\t\tif (this.cache != null) {\n\t\t\tthrow new GradleException(\"Each image building cache can be configured only once\");\n\t\t}\n\t\tBindCacheSpec spec = this.objectFactory.newInstance(BindCacheSpec.class);\n\t\taction.execute(spec);\n\t\tthis.cache = Cache.bind(spec.getSource().get());\n\t}","sourceCodeStart":41,"sourceCodeEnd":77,"githubUrl":"https://github.com/spring-projects/spring-boot/blob/5b2dbdbb8be64415eb6552f81ff7c449c8d251e6/build-plugin/spring-boot-gradle-plugin/src/main/java/org/springframework/boot/gradle/tasks/bundling/LocalCacheSpec.java#L41-L77","documentation":"Thrown by LocalCacheSpec.volume() when the local cache (buildWorkspace or launchCache) has already been configured (this.cache != null). volume and bind are mutually exclusive on a LocalCacheSpec; the second call throws GradleException at line 59.","triggerScenarios":"Calling buildWorkspace { volume { name = 'ws-vol' } } after buildWorkspace { bind {...} }, or calling volume twice — the second invocation sees this.cache already set.","commonSituations":"Applying both a bind and volume config to the same buildWorkspace/launchCache; copy-paste during migration between strategies; convention plugin plus local override.","solutions":["Configure buildWorkspace (or launchCache) with exactly one of volume/bind.","Remove the prior block before switching cache type.","Search the build (and applied init scripts) for buildWorkspace/launchCache to locate duplicates."],"exampleFix":"// before: bind then volume on the same workspace\nbootBuildImage {\n    buildWorkspace { bind { source = '/tmp/ws' } }\n    buildWorkspace { volume { name = 'ws-vol' } } // throws\n}\n// after: single workspace cache\nbootBuildImage {\n    buildWorkspace { volume { name = 'ws-vol' } }\n}\n","handlingStrategy":"validation","validationCode":"var localCacheConfigured = false\nfun configureWorkspaceVolume(name: String) {\n    check(!localCacheConfigured) { \"buildWorkspace cache already configured\" }\n    localCacheConfigured = true\n    // ... buildWorkspace { volume { this.name = name } }\n}\n","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Configure buildWorkspace and launchCache each with a single cache type.","Search for 'buildWorkspace {' and 'launchCache {' across the build before adding new config.","Replace, do not stack, when switching between volume and bind."],"tags":["gradle","boot-build-image","cache","configuration","validation"],"analyzedSha":"5b2dbdbb8be64415eb6552f81ff7c449c8d251e6","analyzedAt":"2026-08-04T18:53:14.967Z","schemaVersion":2}