elastic/elasticsearch · error · UncheckedIOException
Failed to create output directory
Error message
Failed to create output directory
What it means
Thrown by ExtractForeignApiTask.ExtractionWorkAction.execute when Files.createDirectories(outputPath.getParent()) fails with IOException, wrapped as UncheckedIOException. The worker extracts java.lang.foreign classes from the running JDK's jrt:/ image into an output jar, so it first needs the output jar's parent directory to exist.
Source
Thrown at build-tools-internal/src/main/java/org/elasticsearch/gradle/internal/ExtractForeignApiTask.java:156
/**
* Extraction logic that executes inside the forked JDK 21 worker process.
* Reads {@code java.lang.foreign} classes from the worker's own {@code jrt:/} image, so there
* are no cross-JDK module-format compatibility concerns.
*/
public abstract static class ExtractionWorkAction implements WorkAction<ExtractionParameters> {
private static final Logger LOGGER = Logging.getLogger(ExtractionWorkAction.class);
@Override
public void execute() {
checkRuntimeJava21();
Path outputPath = getParameters().getOutputJar().getAsFile().get().toPath();
try {
Files.createDirectories(outputPath.getParent());
} catch (IOException e) {
throw new UncheckedIOException("Failed to create output directory", e);
}
FileSystem jrtFs = FileSystems.getFileSystem(URI.create("jrt:/"));
Path foreignRoot = jrtFs.getPath("modules", "java.base", "java", "lang", "foreign");
int count = 0;
try (
JarOutputStream jar = new JarOutputStream(Files.newOutputStream(outputPath));
Stream<Path> walk = Files.walk(foreignRoot)
) {
for (Path file : (Iterable<Path>) walk::iterator) {
if (Files.isRegularFile(file) == false || file.getFileName().toString().endsWith(".class") == false) {
continue;
}
byte[] stubBytes;
try (InputStream is = Files.newInputStream(file)) {
stubBytes = createStub(is);
}View on GitHub (pinned to db6a809a66)
Solutions
- Check the outputJar task property resolves to a writable, valid path.
- Ensure no regular file occupies the intended parent directory.
- Verify write permissions on the build output root.
- Clean the build outputs so stale files are removed.
Defensive patterns
Strategy: validation
Validate before calling
Path parent = getParameters().getOutputJar().getAsFile().get().toPath().getParent();
if (Files.exists(parent) == false && parent != null) {
// will attempt createDirectories; check writability of nearest existing ancestor
Path ancestor = parent;
while (ancestor != null && Files.exists(ancestor) == false) ancestor = ancestor.getParent();
if (ancestor != null && Files.isWritable(ancestor) == false) {
throw new UncheckedIOException("Cannot create output directory " + parent, new IOException("not writable"));
}
} Try / catch
try {
Files.createDirectories(outputPath.getParent());
} catch (IOException e) {
throw new UncheckedIOException("Failed to create output directory", e);
} Prevention
- Configure outputJar to a writable, valid path.
- Ensure no regular file occupies the intended parent directory.
- Clean build outputs so stale files do not block directory creation.
When it happens
Trigger: The configured outputJar path has a parent that cannot be created - invalid path, permission denied, or a parent component names an existing non-directory file.
Common situations: outputJar property misconfigured to an unwritable or invalid path; build output dir on read-only filesystem; stale file occupying the parent path.
Related errors
- Unable to create reaper JAR output directory {}
- Failed to patch archive
- Failed to unpack {} with checksum {}
- Cannot create directory '%s' as it already exists, but is no
- Cannot create parent directory '%s' when creating directory
AI-assisted analysis of elastic/elasticsearch@db6a809a66 (2026-08-12).
Data as JSON: /api/errors/59602c3310679af5.
Report an issue: GitHub.