apache/druid · error · IOException
directory[ ] is not a directory
Error message
directory[%s] is not a directory
What it means
CompressionUtils.zip compresses a directory tree into a ZIP stream and validates upfront that the given File is actually a directory; if it is a regular file, symlink target, or does not exist as a directory, it throws this IOException. The check prevents the subsequent listFiles() null-dereference and misdirected zipping.
Solutions
- Verify the path is a directory before calling: file.isDirectory() (and exists())
- Point zip() at the parent directory if the intent was to archive a single file — or use file-copy helpers for single files
- Fix the configured directory path in job/spec config that resolved to a file
- Create the directory if it is legitimately missing (FileUtils.mkdirhier) before zipping
Example fix
// before
CompressionUtils.zip(new File("/data/segments/segment-file"), out); // throws
// after
File dir = new File("/data/segments/my-segment");
if (!dir.isDirectory()) {
throw new IllegalArgumentException("Expected a directory: " + dir);
}
CompressionUtils.zip(dir, out); Defensive patterns
Strategy: validation
Validate before calling
File dir = new File(path);
if (!dir.isDirectory()) {
throw new IllegalArgumentException("Not a directory: " + path);
} Try / catch
try {
CompressionUtils.zip(dir, out);
} catch (IOException e) {
if (e.getMessage() != null && e.getMessage().contains("is not a directory")) {
// fix path / abort job
} else throw e;
} Prevention
- Call file.isDirectory() before zip()
- Resolve symlinks before passing paths
- Validate configured directory paths at job start
When it happens
Trigger: Calling CompressionUtils.zip(File, OutputStream) with a path that points to a single file instead of a directory, or with a path that no longer exists (deleted between listing and zipping, or a wrong configured path).
Common situations: Configured task/restore directory paths pointing at files; symlinks resolved to files; jobs archiving segment directories after they were replaced by files in newer layouts.
Related errors
- file[ ] too large [%,d]
- Directory compression not supported for
- Directory decompression not supported for
- NONE compression strategy shouldn't use any compressor
- NONE compression strategy shouldn't use any decompressor
AI-assisted analysis of apache/druid@9b90983fd2 (2026-09-07).
Data as JSON: /api/errors/afe662c28a6aa935.
Report an issue: GitHub.
Appendix: source
Thrown at processing/src/main/java/org/apache/druid/utils/CompressionUtils.java:265
public static long zip(File directory, File outputZipFile) throws IOException
{
return zip(directory, outputZipFile, false);
}
/**
* Zips the contents of the input directory to the output stream. Sub directories are skipped
*
* @param directory The directory whose contents should be added to the zip in the output stream.
* @param out The output stream to write the zip data to. Caller is responsible for closing this stream.
*
* @return The number of bytes (uncompressed) read from the input directory.
*
* @throws IOException
*/
public static long zip(File directory, OutputStream out) throws IOException
{
if (!directory.isDirectory()) {
throw new IOE("directory[%s] is not a directory", directory);
}
final ZipOutputStream zipOut = new ZipOutputStream(out);
long totalSize = 0;
// Sort entries to make life easier when writing streaming-decompression unit tests.
for (File file : Arrays.stream(directory.listFiles()).sorted().collect(Collectors.toList())) {
log.debug("Adding file[%s] with size[%,d]. Total size so far[%,d]", file, file.length(), totalSize);
if (file.length() > Integer.MAX_VALUE) {
zipOut.finish();
throw new IOE("file[%s] too large [%,d]", file, file.length());
}
zipOut.putNextEntry(new ZipEntry(file.getName()));
totalSize += Files.asByteSource(file).copyTo(zipOut);
}
zipOut.closeEntry();
// Workaround for http://hg.openjdk.java.net/jdk8/jdk8/jdk/rev/759aa847dcafView on GitHub (pinned to 9b90983fd2)