{"record":{"id":"f28e98b984694b35","repo":"elastic/elasticsearch","slug":"can-t-create-extra-config-file-from-for-as-i","errorCode":null,"errorMessage":"Can't create extra config file from {} for {} as it does not exist","messagePattern":"Can't create extra config file from (.+?) for (.+?) as it does not exist","errorType":"exception","errorClass":"TestClustersException","httpStatus":null,"severity":"error","filePath":"build-tools/src/main/java/org/elasticsearch/gradle/testclusters/ElasticsearchNode.java","lineNumber":618,"sourceCode":"        if (currentDistro + 1 >= distributions.size()) {\n            throw new TestClustersException(\"Ran out of versions to go to for \" + this);\n        }\n        logToProcessStdout(\"Switch version from \" + getVersion() + \" to \" + distributions.get(currentDistro + 1).getVersion());\n        currentDistro += 1;\n        setting(\"node.attr.upgraded\", \"true\");\n    }\n\n    private boolean isSettingTrue(String name) {\n        return Boolean.parseBoolean(settings.getOrDefault(name, \"false\").toString());\n    }\n\n    private void copyExtraConfigFiles() {\n        if (extraConfigFiles.isEmpty() == false) {\n            logToProcessStdout(\"Setting up \" + extraConfigFiles.size() + \" additional config files\");\n        }\n        extraConfigFiles.forEach((destination, from) -> {\n            if (Files.exists(from.toPath()) == false) {\n                throw new TestClustersException(\"Can't create extra config file from \" + from + \" for \" + this + \" as it does not exist\");\n            }\n            Path dst = configFile.getParent().resolve(destination);\n            try {\n                Files.createDirectories(dst.getParent());\n                Files.copy(from.toPath(), dst, StandardCopyOption.REPLACE_EXISTING);\n                LOGGER.info(\"Added extra config file {} for {}\", destination, this);\n            } catch (IOException e) {\n                throw new UncheckedIOException(\"Can't create extra config file for\", e);\n            }\n        });\n    }\n\n    /**\n     * Copies extra jars to the `/lib` directory.\n     * //TODO: Remove this when system modules are available\n     */\n    private void copyExtraJars() {\n        List<File> extraJarFiles = this.extraJarConfigurations.stream()","sourceCodeStart":600,"sourceCodeEnd":636,"githubUrl":"https://github.com/elastic/elasticsearch/blob/db6a809a667c081ca1dc7500389d26975573215f/build-tools/src/main/java/org/elasticsearch/gradle/testclusters/ElasticsearchNode.java#L600-L636","documentation":"Thrown by copyExtraConfigFiles() during start() when an entry registered via extraConfigFile(destination, from) points to a source File whose path does not exist (Files.exists check). The node refuses to copy a non-existent file into its config directory because that would silently produce a missing config entry and a confusing downstream startup failure.","triggerScenarios":"Calling extraConfigFile('log4j2.xml', file) where file resolves to a path that does not exist at start time. Because the map stores File references lazily, the check fires during start() rather than at registration, so a typo or a not-yet-generated source surfaces here.","commonSituations":"Source config file generated by another Gradle task that was not wired as a dependency. Path relative to the wrong subproject. Typo in filename. Resource stripped on a branch. CI checkout missing the file.","solutions":["Verify the path from the message exists at the moment the cluster starts.","If generated, pass a Provider<File> or wire the producing task as a dependency so Gradle materialises it first.","Use project.layout.projectDirectory.file('config/x.xml') for checked-in files to make the path unambiguous.","Remove the extraConfigFile call if the file is no longer needed; do not register dead config."],"exampleFix":"// before: file does not exist yet\nextraConfigFile('log4j2.xml', new File('src/test/resources/log4j2.xml'))\n// after: resolve from project dir and ensure the file is committed\nextraConfigFile('log4j2.xml', project.layout.projectDirectory.file('src/test/resources/log4j2.xml').asFile)","handlingStrategy":"validation","validationCode":"node.getExtraConfigFiles().forEach((dest, from) -> {\n    if (!Files.exists(from.toPath())) {\n        throw new IllegalStateException(\"extraConfigFile source missing for dest \" + dest + \": \" + from);\n    }\n});\n// Prefer Provider<File> sourced from the producing task so Gradle materialises it before start().","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Use project.layout.projectDirectory.file(...) for checked-in config.","Wire generated config through task outputs.","Do not register extraConfigFile entries you no longer need."],"tags":["testclusters","config","filesystem","validation"],"backgroundTag":null,"analyzedSha":"db6a809a667c081ca1dc7500389d26975573215f","analyzedAt":"2026-08-12T01:39:14.192Z","schemaVersion":2},"datasetVersion":"2026-08-12T13:17:24.610Z"}