elastic/elasticsearch · error · TestClustersException

supplied keystore file {} does not exist, require for {}

Error message

supplied keystore file {} does not exist, require for {}

What it means

Thrown during start() after keystore files are registered but before invoking elasticsearch-keystore add-file. The code requires a non-null File (requireNonNull) AND that file.exists() is true; a missing source file aborts keystore provisioning. This protects the keystore command from being handed a nonexistent path, which would otherwise surface as an opaque CLI error.

Source

Thrown at build-tools/src/main/java/org/elasticsearch/gradle/testclusters/ElasticsearchNode.java:542

        }

        logToProcessStdout("Creating elasticsearch keystore with password set to [" + keystorePassword + "]");
        if (keystorePassword.length() > 0) {
            runElasticsearchBinScriptWithInput(keystorePassword + "\n" + keystorePassword, "elasticsearch-keystore", "create", "-p");
        } else {
            runElasticsearchBinScript("elasticsearch-keystore", "-v", "create");
        }

        if (keystoreSettings.isEmpty() == false || keystoreFiles.isEmpty() == false) {
            logToProcessStdout("Adding " + keystoreSettings.size() + " keystore settings and " + keystoreFiles.size() + " keystore files");

            keystoreSettings.forEach((key, value) -> runKeystoreCommandWithPassword(keystorePassword, value.toString(), "add", key));

            for (Map.Entry<String, File> entry : keystoreFiles.entrySet()) {
                File file = entry.getValue();
                requireNonNull(file, "supplied keystoreFile was null when configuring " + this);
                if (file.exists() == false) {
                    throw new TestClustersException("supplied keystore file " + file + " does not exist, require for " + this);
                }
                runKeystoreCommandWithPassword(keystorePassword, "", "add-file", entry.getKey(), file.getAbsolutePath());
            }
        }

        installModules();

        if (isSettingTrue("xpack.security.enabled")) {
            if (credentials.isEmpty()) {
                user(Collections.emptyMap());
            }
        }

        configureSecurity();

        if (cliSetup.isEmpty() == false) {
            logToProcessStdout("Running " + cliSetup.size() + " setup commands");

View on GitHub (pinned to db6a809a66)

Solutions

  1. Verify the path printed in the message exists on disk at the time the test cluster starts: ls -la <path>.
  2. If the file is generated by another task, wire it through a Provider/FileCollection so Gradle creates the task dependency, e.g. keystoreFile('my.setting', generateKeyTask.flatMap { it.outputFile }).
  3. If it is a checked-in resource, confirm it is committed and (for git-lfs) pulled on the CI agent.
  4. Use an absolute path or resolve via project.layout.projectDirectory.file(...) to avoid working-directory ambiguity.

Example fix

// before: static file path that may not exist
keystoreFile('bootstrap.password', new File('certs/key.txt'))
// after: wire a task output as a provider so it exists before start
keystoreFile('bootstrap.password', generateKeyTask.flatMap { it.outputFile.asFile })
Defensive patterns

Strategy: validation

Validate before calling

// Validate keystore files exist before starting
node.getKeystoreFiles().forEach((k, f) -> {
    requireNonNull(f, "keystoreFile null for key " + k);
    if (!f.exists()) {
        throw new IllegalStateException("keystoreFile missing for key " + k + ": " + f);
    }
});
// Prefer wiring task outputs as providers so Gradle builds them before start().

Prevention

When it happens

Trigger: Calling keystoreFile(settingKey, file) with a File whose path is wrong, generated by a task that has not produced it yet, located outside the Gradle project root, or resolved relative to the wrong working directory. Because LazyPropertyMap is lazy, the existence check fires at start() time, not at registration time.

Common situations: Referencing a generated file (cert, key material) whose producing task was not declared as an input dependency of the test cluster. Typo in the path. File created in a different subproject's build dir. Resource path resolved against the wrong project. CI checked out without large files / git-lfs objects.

Related errors


AI-assisted analysis of elastic/elasticsearch@db6a809a66 (2026-08-12). Data as JSON: /api/errors/414358343e539582. Report an issue: GitHub.