elastic/elasticsearch · error · TestClustersException
Can't create roles.yml config file from {} for {} as it does
Error message
Can't create roles.yml config file from {} for {} as it does not exist What it means
Thrown by configureSecurity() during start() when a File added via rolesFile(from) does not exist (Files.exists false). Symmetric to the extra-config-file check, this guards the roles.yml append step so that a missing source file fails loudly instead of silently producing an incomplete roles file.
Source
Thrown at build-tools/src/main/java/org/elasticsearch/gradle/testclusters/ElasticsearchNode.java:678
logToProcessStdout("Setting up " + credentials.size() + " users");
credentials.forEach(
paramMap -> runElasticsearchBinScript(
getVersion().onOrAfter("6.3.0") ? "elasticsearch-users" : "x-pack/users",
paramMap.entrySet().stream().flatMap(entry -> Stream.of(entry.getKey(), entry.getValue())).toArray(String[]::new)
)
);
// If we added users, then also add the standard test roles
rolesFile(getBuildPluginFile("/roles.yml"));
}
if (roleFiles.isEmpty() == false) {
logToProcessStdout("Setting up roles.yml");
Path dst = configFile.getParent().resolve("roles.yml");
roleFiles.forEach(from -> {
if (Files.exists(from.toPath()) == false) {
throw new TestClustersException(
"Can't create roles.yml config file from " + from + " for " + this + " as it does not exist"
);
}
try {
final Path source = from.toPath();
final String content = Files.readString(source, StandardCharsets.UTF_8);
Files.writeString(dst, content + System.lineSeparator(), StandardCharsets.UTF_8, StandardOpenOption.APPEND);
LOGGER.info("Appended roles file {} to {}", source, dst);
} catch (IOException e) {
throw new UncheckedIOException("Can't append roles file " + from + " to " + dst, e);
}
});
}
}
private void installModules() {
logToProcessStdout("Installing " + modules.size() + " modules");
for (Provider<File> module : modules) {View on GitHub (pinned to db6a809a66)
Solutions
- Verify the path in the message exists at start time.
- If generated, pass the producing task's output as a Provider so Gradle builds it first.
- If the failing source is the bundled /roles.yml, ensure the build-tools jar providing that resource is on the test classpath (not stripped by shading).
- Use an absolute or project-relative path resolved via project.layout.projectDirectory.
Example fix
// before: relative file that may not resolve
rolesFile(new File('roles/custom.yml'))
// after: project-relative, generated task output wired in
rolesFile(generateRolesTask.flatMap { it.outputFile.asFile }) Defensive patterns
Strategy: validation
Validate before calling
node.getRoleFiles().forEach(f -> {
if (!Files.exists(f.toPath())) {
throw new IllegalStateException("rolesFile source missing: " + f);
}
});
// If generated, wire Provider<File> from the producing task. Prevention
- Use project-relative paths via project.layout.projectDirectory.
- Wire generated roles through task outputs.
- Ensure the build-tools /roles.yml bundled resource is on the test classpath.
When it happens
Trigger: Calling node.rolesFile(file) with a File that is wrong, generated-too-late, outside the project tree, or missing on the CI checkout. Note configureSecurity() also auto-adds getBuildPluginFile('/roles.yml') when credentials are present; if that bundled resource is unreachable (classpath issue) the same throw fires.
Common situations: Custom roles file generated by a task not wired as a dependency. Path relative to wrong subproject. Bundled /roles.yml resource missing from the test classpath after a refactor of build-tools resources.
Related errors
- supplied keystore file {} does not exist, require for {}
- Can't append roles file {} to {}
- Can't create extra config file from {} for {} as it does not
- extra config file destination can't be relative, was {} for
- Unknown keys in user definition {} for {}
AI-assisted analysis of elastic/elasticsearch@db6a809a66 (2026-08-12).
Data as JSON: /api/errors/03c816bd426a0ba7.
Report an issue: GitHub.