{"record":{"id":"e14b82eadce44201","repo":"elastic/elasticsearch","slug":"can-t-create-extra-config-file-for","errorCode":null,"errorMessage":"Can't create extra config file for","messagePattern":"Can't create extra config file for","errorType":"exception","errorClass":"UncheckedIOException","httpStatus":null,"severity":"error","filePath":"build-tools/src/main/java/org/elasticsearch/gradle/testclusters/ElasticsearchNode.java","lineNumber":626,"sourceCode":"    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()\n            .flatMap(fileCollection -> fileCollection.getFiles().stream())\n            .toList();\n\n        if (extraJarFiles.isEmpty() == false) {\n            logToProcessStdout(\"Setting up \" + this.extraJarConfigurations.size() + \" additional jar dependencies\");\n        }\n        extraJarFiles.forEach(from -> {\n            if (from.getName().endsWith(\".jar\") == false) {","sourceCodeStart":608,"sourceCodeEnd":644,"githubUrl":"https://github.com/elastic/elasticsearch/blob/db6a809a667c081ca1dc7500389d26975573215f/build-tools/src/main/java/org/elasticsearch/gradle/testclusters/ElasticsearchNode.java#L608-L644","documentation":"Thrown by copyExtraConfigFiles() when Files.createDirectories / Files.copy raises an IOException while materialising an extra config file (source existed, but the copy itself failed). The IOException is wrapped in an UncheckedIOException with the generic message 'Can't create extra config file for' (note: the message is a prefix; the cause carries the detail).","triggerScenarios":"Source file passes the existence check but the destination parent cannot be created or the bytes cannot be written: permissions on the distro config dir, read-only filesystem, antivirus interference, path-too-long, or a name collision with an existing directory.","commonSituations":"Windows MAX_PATH exceeded in deep testclusters paths. Antivirus locking destination on Windows CI. Permission residue from a prior root-owned run. Disk full mid-copy. Destination path collides with a directory created by setupNodeDistribution.","solutions":["Inspect the wrapped IOException (cause) for the precise FS error and address it (permissions, disk, path length).","On Windows, shorten the build path / enable long-path support.","Clear build/testclusters and rerun so setupNodeDistribution recreates a clean distro dir.","Confirm the destination string does not collide with an existing directory under config/."],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":"// Confirm destination parent is writable and not a colliding file\nPath configParent = node.getConfigFile().getParent();\nif (!Files.isWritable(configParent)) {\n    throw new IllegalStateException(\"Config dir not writable: \" + configParent);\n}","typeGuard":null,"tryCatchPattern":"try {\n    node.start();\n} catch (UncheckedIOException e) {\n    if (e.getMessage().contains(\"extra config file\")) {\n        // surface FS cause: perms / disk / AV\n        throw new IllegalStateException(\"Config copy failed at FS level: \" + e.getCause(), e);\n    }\n    throw e;\n}","preventionTips":["Keep build/testclusters owned by the Gradle user.","Shorten build paths on Windows.","Disable or tune AV exclusions for the build dir on Windows CI."],"tags":["testclusters","config","io","filesystem"],"analyzedSha":"db6a809a667c081ca1dc7500389d26975573215f","analyzedAt":"2026-08-12T01:39:14.192Z","schemaVersion":2},"datasetVersion":"2026-08-12T12:17:08.281Z"}