apache/flink · error · IOException

{directory} is not a directory

Error message

{directory} is not a directory

What it means

Thrown by FileUtils.deleteDirectory when the given path exists but is a regular file. deleteDirectory is only meaningful for directories; deleting a file at that path would exceed the caller's intent, so it fails fast instead of guessing.

Source

Thrown at flink-core/src/main/java/org/apache/flink/util/FileUtils.java:338

            // directory exists and is a directory

            // empty the directory first
            try {
                cleanDirectoryInternal(directory);
            } catch (FileNotFoundException ignored) {
                // someone concurrently deleted the directory, nothing to do for us
                return;
            }

            // delete the directory. this fails if the directory is not empty, meaning
            // if new files got concurrently created. we want to fail then.
            // if someone else deleted the empty directory concurrently, we don't mind
            // the result is the same for us, after all
            Files.deleteIfExists(directory.toPath());
        } else if (directory.exists()) {
            // exists but is file, not directory
            // either an error from the caller, or concurrently a file got created
            throw new IOException(directory + " is not a directory");
        }
        // else: does not exist, which is okay (as if deleted)
    }

    private static void cleanDirectoryInternal(File directory) throws IOException {
        if (Files.isSymbolicLink(directory.toPath())) {
            // the user directories which symbolic links point to should not be cleaned.
            return;
        }
        if (directory.isDirectory()) {
            final File[] files = directory.listFiles();

            if (files == null) {
                // directory does not exist any more or no permissions
                if (directory.exists()) {
                    throw new IOException("Failed to list contents of " + directory);
                } else {
                    throw new FileNotFoundException(directory.toString());

View on GitHub (pinned to 2f3c205e92)

Solutions

  1. Check whether the path should really be a directory; if it may be either, use deleteFileOrDirectory instead
  2. Remove the stale file manually or via a pre-clean step, then rerun
  3. Investigate what created a file where a directory was expected — that is usually the actual bug

Example fix

// before
FileUtils.deleteDirectory(new File(path)); // path is a file

// after
File f = new File(path);
if (f.isDirectory()) {
    FileUtils.deleteDirectory(f);
} else if (f.exists()) {
    // deliberate: only files ever expected here
    org.apache.flink.util.Preconditions.checkState(!f.isDirectory(), path);
    f.delete();
}
Defensive patterns

Strategy: type-guard

Validate before calling

File f = new File(path);
if (f.exists() && !f.isDirectory()) {
    throw new IOException("Expected directory, found file: " + f);
}

Type guard

static boolean isDeletableDirectory(File f) { return !f.exists() || f.isDirectory(); }

Try / catch

catch (IOException e) when cleaning best-effort: log and continue if cleanup is non-critical.

Prevention

When it happens

Trigger: Calling FileUtils.deleteDirectory(file) where file exists and isFile() is true; a typical case is a path that used to be a directory but a concurrent process recreated it as a file, or the caller mixed up deleteFileOrDirectory and deleteDirectory.

Common situations: Cleanup code assuming a workspace path is always a directory; races where another process replaced the directory with a symlink target/file; tests pointing cleanup at a file artifact by mistake.

Related errors


AI-assisted analysis of apache/flink@2f3c205e92 (2026-08-14). Data as JSON: /api/errors/0d16c18889c33f2f. Report an issue: GitHub.