elastic/elasticsearch · error · TestClustersException

Can not start {}, is not a directory: {}

Error message

Can not start {}, is not a directory: {}

What it means

Thrown by ElasticsearchNode.start() after confirming the extracted distribution path exists but Files.isDirectory() returns false. The node refuses to boot because the extraction target is a regular file or a broken symlink rather than an unpacked ES home directory. It is a hard precondition guarding every downstream step that walks the distro tree (setupNodeDistribution, bin scripts, lib/modules).

Source

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

        distributions.forEach(ElasticsearchDistribution::maybeFreeze);
        configurationFrozen.set(true);
    }

    private static String throwableToString(Throwable t) {
        StringWriter sw = new StringWriter();
        PrintWriter pw = new PrintWriter(sw);
        t.printStackTrace(pw);
        return sw.toString();
    }

    @Override
    public synchronized void start() {
        LOGGER.info("Starting `{}`", this);
        if (Files.exists(getExtractedDistributionDir()) == false) {
            throw new TestClustersException("Can not start " + this + ", missing: " + getExtractedDistributionDir());
        }
        if (Files.isDirectory(getExtractedDistributionDir()) == false) {
            throw new TestClustersException("Can not start " + this + ", is not a directory: " + getExtractedDistributionDir());
        }

        try {
            if (isWorkingDirConfigured == false) {
                logToProcessStdout("Configuring working directory: " + workingDir);
                // make sure we always start fresh
                if (Files.exists(workingDir)) {
                    if (preserveDataDir) {
                        try (var files = Files.list(workingDir)) {
                            files.filter(path -> path.equals(confPathData) == false).forEach(this::uncheckedDeleteWithRetry);
                        }
                    } else {
                        deleteWithRetry(workingDir);
                    }
                }
                isWorkingDirConfigured = true;
            }
            setupNodeDistribution(getExtractedDistributionDir());

View on GitHub (pinned to db6a809a66)

Solutions

  1. Delete the affected node's working/extracted directory (e.g. rm -rf build/testclusters/<node>) and rerun so the distribution is re-extracted.
  2. Check the distribution configuration: ensure the ElasticsearchDistribution type is one that unpacks to a directory (integ-test-zip or archive types that get extracted), not a raw file artifact.
  3. Verify the distribution download/extraction task ran successfully upstream; inspect the path printed in the message with ls -la to see whether it is a file or a dangling symlink.
  4. Run with --rerun-tasks or clean the testclusters task to force re-extraction.

Example fix

// before: distribution produces a single file, not an unpacked dir
testClusters {
  myNode {
    distribution 'elasticsearch', '8.0.0' // wrong type
  }
}
// after: use the integ-test distribution which extracts to a directory
testClusters {
  myNode {
    distribution 'integ-test-zip', '8.0.0'
  }
}
Defensive patterns

Strategy: validation

Validate before calling

// Run before start() to confirm the extracted distro is a directory
Path distroDir = node.getExtractedDistributionDir();
if (!Files.isDirectory(distroDir)) {
    throw new IllegalStateException("Extracted distro not a directory: " + distroDir
        + " (exists=" + Files.exists(distroDir) + "). Clean build/testclusters and rerun.");
}

Prevention

When it happens

Trigger: Calling testClusters.start() (directly or via a TestClustersTask) when getExtractedDistributionDir() resolves to a file, a stale marker file, or a partially extracted archive whose top-level entry was not a directory. Also when a custom distribution download produced a single artifact instead of an unpacked tree, or a previous run left a corrupt extraction behind.

Common situations: Interrupted/cancelled Gradle build left a half-extracted distribution. Distribution plugin misconfigured to a 'tar'/'zip' type whose extraction step was skipped. Symlink in the build dir pointing to a deleted target. Manual tampering with build/testclusters/. Stale caches after switching distribution type or OS.

Related errors


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