apache/flink · error · IOException

{directory} is not a directory but a regular file

Error message

{directory} is not a directory but a regular file

What it means

Thrown from cleanDirectoryInternal when the path exists but is a regular file. Cleaning operates on directory contents; a file at the path has no 'contents' to clean, so the operation refuses rather than deleting something the caller did not describe.

Source

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

            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());
                }
            }

            // remove all files in the directory
            for (File file : files) {
                if (file != null) {
                    deleteFileOrDirectory(file);
                }
            }
        } else if (directory.exists()) {
            throw new IOException(directory + " is not a directory but a regular file");
        } else {
            // else does not exist at all
            throw new FileNotFoundException(directory.toString());
        }
    }

    private static void guardIfNotThreadSafe(ThrowingConsumer<File, IOException> toRun, File file)
            throws IOException {
        if (OperatingSystem.isWindows()) {
            guardIfWindows(toRun, file);
            return;
        }
        if (OperatingSystem.isMac()) {
            guardIfMac(toRun, file);
            return;
        }

        toRun.accept(file);

View on GitHub (pinned to 2f3c205e92)

Solutions

  1. Inspect the path — decide whether it should be deleted as a file or the config should point elsewhere
  2. Delete the offending file and recreate the directory before rerunning cleanup
  3. Validate configuration paths at startup (expectDirectory) so mistakes surface early with context

Example fix

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

// after
File f = new File(path);
if (f.exists() && !f.isDirectory()) {
    throw new IllegalStateException("Expected directory but found file at " + path
        + " - check configuration");
}
FileUtils.cleanDirectory(f);
Defensive patterns

Strategy: type-guard

Validate before calling

File d = new File(path);
if (d.exists() && !d.isDirectory()) {
    throw new IllegalStateException("Path is a file, expected directory: " + path);
}

Type guard

static boolean isCleanableDirectory(File f) { return !f.exists() || Files.isDirectory(f.toPath()); } // note: symlink-to-dir is skipped by cleanDirectory itself

Try / catch

catch (IOException e) and surface the misconfigured path to the operator; this is a configuration/state bug, not transient.

Prevention

When it happens

Trigger: Calling FileUtils.cleanDirectory on a path that is a file — e.g. a leftover archive recreated at the directory's location, or a symlink-to-file resolved to a non-directory (note: symlinked directories return early instead).

Common situations: State store / cache dir replaced by a file after a misconfigured run; path configuration pointing at a file (wrong key, trailing filename); remnants of previous experiments in temp dirs.

Related errors


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