elastic/elasticsearch · error · GradleException

Failed to create output directory: {outputDir}

Error message

Failed to create output directory: {outputDir}

What it means

Thrown inside NativeImageBuildAction.execute() (a Gradle WorkAction) when the output directory for the native-image binary cannot be created. The code checks if the parent directory of the configured output file exists; if not, it calls mkdirs(). If mkdirs() returns false and the directory still does not exist, it throws GradleException. This runs inside a Gradle worker with no isolation, so filesystem errors surface directly.

Source

Thrown at build-tools-internal/src/main/java/org/elasticsearch/gradle/internal/docker/NativeImageBuildTask.java:157

        private final ExecOperations execOperations;

        @Inject
        public NativeImageBuildAction(ExecOperations execOperations) {
            this.execOperations = execOperations;
        }

        @Override
        public void execute() {
            Parameters params = getParameters();
            String imageTag = params.getImageTag().get();
            String platform = params.getPlatform().get();
            String mainClass = params.getMainClass().get();
            File outputFile = params.getOutputFile().get().getAsFile();
            File outputDir = outputFile.getParentFile();

            if (outputDir.exists() == false && outputDir.mkdirs() == false) {
                throw new GradleException("Failed to create output directory: " + outputDir);
            }

            List<File> classpathFiles = params.getClasspath().getFiles().stream().filter(File::exists).collect(Collectors.toList());
            if (classpathFiles.isEmpty()) {
                throw new GradleException("Native-image classpath is empty");
            }

            // Build classpath string for inside the container: /cp/0:/cp/1:...
            List<String> cpPaths = new ArrayList<>();
            for (int i = 0; i < classpathFiles.size(); i++) {
                cpPaths.add("/cp/" + i);
            }
            // Container is always Linux
            String cpString = String.join(":", cpPaths);

            List<String> args = new ArrayList<>();
            args.add("run");
            args.add("--rm");

View on GitHub (pinned to db6a809a66)

Solutions

  1. Check if any path component of the output file's parent is a regular file rather than a directory: inspect the path manually.
  2. Ensure the Gradle daemon process has write permissions to the output location: ls -la on the parent directory chain.
  3. If using a custom output file, set it to an absolute path within the project's build directory: getOutputFile().set(project.getLayout().getBuildDirectory().file('native-image/output')).
  4. Run a clean build to clear any stale file/directory conflicts: ./gradlew clean.

Example fix

// before
nativeImageBuild {
    outputFile = file('/opt/native-images/app') // parent /opt/native-images may not exist or be read-only
}

// after
nativeImageBuild {
    outputFile = layout.buildDirectory.file('native-image/app') // within writable build dir
}
Defensive patterns

Strategy: validation

Validate before calling

// Validate output directory before task execution
File outputDir = outputFile.getParentFile();
if (outputDir != null && !outputDir.exists()) {
    if (!outputDir.getCanonicalPath().startsWith(project.getBuildDir().getCanonicalPath())) {
        throw new GradleException("Output directory is outside build dir: " + outputDir);
    }
}

Prevention

When it happens

Trigger: The configured OutputFile's parent directory does not exist, File.mkdirs() returns false. This happens when: a parent path component is a regular file (not a directory), the path is on a read-only filesystem, permissions prevent creation, or the path is invalid for the OS.

Common situations: The output file path is configured with a relative path that resolves to an unexpected location. A parent path component (e.g., 'build/native-image') conflicts with a file of the same name. The build output directory is on a network mount or read-only volume. The Gradle daemon process lacks write permission to the configured output location.

Related errors


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