elastic/elasticsearch · error · IOException
Could not create directory
Error message
Could not create directory: {packageDir} What it means
Thrown by GenerateEsqlSpecTestsTask.generate() when the package directory for generated ES|QL spec test source files cannot be created. The task deletes the output directory, then derives a package path from the configured package name (converting dots to slashes) and calls mkdirs(). If mkdirs() returns false AND the directory does not exist afterward, it throws IOException.
Solutions
- Run ./gradlew clean to remove stale output directories that may conflict with file-typed path components.
- Verify the packageName property resolves to a valid path: ensure it contains no path separators or invalid characters.
- Ensure the Gradle daemon has write permissions to the output directory location.
- Check that getOutputDirectory() is set to a writable location within the project's build directory.
Defensive patterns
Strategy: validation
Validate before calling
// Validate output directory writability
File outputDir = getOutputDirectory().getAsFile().get();
File parent = outputDir.getParentFile();
if (parent != null && parent.exists() && !parent.canWrite()) {
throw new GradleException("Cannot write to output directory: " + outputDir);
} Prevention
- Run ./gradlew clean to remove stale files that may conflict with directory creation.
- Keep generated output within the build directory.
- Verify the package name property contains only valid Java identifier characters.
When it happens
Trigger: The output directory is deleted via FileSystemOperations.delete, then packageDir.mkdirs() is called. mkdirs() returns false if a parent path component is a regular file, if permissions are insufficient, or if the path is read-only. The check `mkdirs() == false && exists() == false` handles the race where mkdirs returns false because the directory already existed (created by a concurrent process), but a genuine failure propagates.
Common situations: The output directory path conflicts with a file of the same name left by a previous incomplete build. The build runs on a read-only filesystem or a CI agent with restricted write access. The package name property is misconfigured, producing a path that resolves outside the project build directory.
Related errors
- Cannot generate source from String template
- Could not create output directory
- Failed to create output directory
- variantPrefixes, variantBaseClasses, and…
- Can't append roles file
AI-assisted analysis of elastic/elasticsearch@db6a809a66 (2026-08-12).
Data as JSON: /api/errors/69fe3bb912791d84.
Report an issue: GitHub.
Appendix: source
Thrown at build-tools-internal/src/main/java/org/elasticsearch/gradle/internal/esql/GenerateEsqlSpecTestsTask.java:93
@Input
public abstract ListProperty<String> getVariantSpecFilePatterns();
@OutputDirectory
public abstract DirectoryProperty getOutputDirectory();
@Inject
public abstract FileSystemOperations getFileSystemOperations();
@TaskAction
public void generate() throws IOException {
File outputDir = getOutputDirectory().getAsFile().get();
getFileSystemOperations().delete(spec -> spec.delete(outputDir));
String packageName = getPackageName().get();
String packagePath = packageName.replace('.', '/');
File packageDir = new File(outputDir, packagePath);
if (packageDir.mkdirs() == false && packageDir.exists() == false) {
throw new IOException("Could not create directory: " + packageDir);
}
List<String> prefixes = getVariantPrefixes().get();
List<String> baseClasses = getVariantBaseClasses().get();
List<String> allEncodedPatterns = getVariantSpecFilePatterns().get();
if (prefixes.size() != baseClasses.size() || prefixes.size() != allEncodedPatterns.size()) {
throw new IllegalStateException("variantPrefixes, variantBaseClasses, and variantSpecFilePatterns must have the same length");
}
File specDir = getSpecFilesDir().getAsFile().get();
File[] specFiles = specDir.listFiles((dir, name) -> name.endsWith(".csv-spec"));
if (specFiles == null) {
return;
}
Arrays.sort(specFiles);
for (File specFile : specFiles) {
String specFileName = specFile.getName();
String baseName = specFileName.substring(0, specFileName.length() - ".csv-spec".length());View on GitHub (pinned to db6a809a66)