apache/pulsar · error · IOException
${dir} is not a directory
Error message
${dir} is not a directory What it means
FileUtils.ensureDirectoryExistAndCanReadAndWrite(dir) prepares a directory that must exist and be readable/writable. If the File exists but is a regular file (or other non-directory), it throws IOException '<abs path> is not a directory' because a file occupies the path where a directory is required. It will happily create the directory if missing, but never overwrite an existing file.
Source
Thrown at pulsar-common/src/main/java/org/apache/pulsar/common/nar/FileUtils.java:81
final MessageDigest digest = MessageDigest.getInstance("SHA-256");
final byte[] buffer = new byte[8192];
int read = inputStream.read(buffer);
while (read > -1) {
digest.update(buffer, 0, read);
read = inputStream.read(buffer);
}
return digest.digest();
} catch (NoSuchAlgorithmException nsae) {
throw new IllegalArgumentException(nsae);
}
}
public static void ensureDirectoryExistAndCanReadAndWrite(final File dir) throws IOException {
if (dir.exists() && !dir.isDirectory()) {
throw new IOException(dir.getAbsolutePath() + " is not a directory");
} else if (!dir.exists()) {
final boolean made = dir.mkdirs();
if (!made) {
throw new IOException(dir.getAbsolutePath() + " could not be created");
}
}
if (!(dir.canRead() && dir.canWrite())) {
throw new IOException(dir.getAbsolutePath() + " directory does not have read/write privilege");
}
}
public static void ensureDirectoryExistAndCanRead(final File dir) throws IOException {
if (dir.exists() && !dir.isDirectory()) {
throw new IOException(dir.getAbsolutePath() + " is not a directory");
} else if (!dir.exists()) {
final boolean made = dir.mkdirs();
if (!made) {
throw new IOException(dir.getAbsolutePath() + " could not be created");View on GitHub (pinned to 820761864e)
Solutions
- Inspect the path (ls -la) and remove or rename the file occupying it, then retry so the code can mkdirs.
- Fix the configuration property pointing at this path so it names a dedicated directory.
- In containers/orchestrators, mount a volume/directory, not a single file, at that path.
Example fix
// before
File dir = new File(config.getNarDir()); // path is a leftover file
FileUtils.ensureDirectoryExistAndCanReadAndWrite(dir);
// after
File dir = new File(config.getNarDir());
if (dir.exists() && !dir.isDirectory()) {
dir.delete(); // or move it aside
}
FileUtils.ensureDirectoryExistAndCanReadAndWrite(dir); Defensive patterns
Strategy: validation
Validate before calling
File dir = new File(path);
if (dir.exists() && !dir.isDirectory()) {
throw new IllegalStateException("Path is a file, expected directory: " + path);
} Try / catch
try {
FileUtils.ensureDirectoryExistAndCanReadAndWrite(dir);
} catch (IOException e) {
// e.getMessage() ends with 'is not a directory' -> move file aside or fail config
throw new IllegalStateException("Fix path " + dir + ": " + e.getMessage(), e);
} Prevention
- Check the configured path with ls -la at startup and fail fast with a clear message
- Dedicate separate paths for files and directories in config
- In containers, mount volumes as directories at these paths
When it happens
Trigger: Passing a File whose path already exists as a regular file (or symlink to a file) to ensureDirectoryExistAndCanReadAndWrite.
Common situations: NAR extraction/cache directories (e.g. the narExtractBundleDirectory config) pointing at a path where a stale file was created earlier, a previous misconfiguration wrote a file at the expected directory path, or a container mount maps a file instead of a directory.
Related errors
- Cannot create ${parentDirectory}
- ${dir} directory does not have read/write privilege
- Cannot create ${narExtractionTempDirectory}
- Failed to load the additional servlet for name `${servletNam
- Failed to read decryption key from ${keyUri}
AI-assisted analysis of apache/pulsar@820761864e (2026-09-06).
Data as JSON: /api/errors/9b3a21a4a9f90ea7.
Report an issue: GitHub.