apache/pulsar · error · IOException
Unable to list directory content in: ${directory}
Error message
Unable to list directory content in: ${directory} What it means
FileUtils.deleteFilesInDirectory lists the directory via File.listFiles() before deleting entries; listFiles() returns null not only for non-directories but also when an I/O error occurs while listing, in which case the method throws IOException 'Unable to list directory content in: <abs path>'. This guards against silently treating an unreadable directory as empty.
Source
Thrown at pulsar-common/src/main/java/org/apache/pulsar/common/nar/FileUtils.java:153
* this is printed at warn to the given logger.
*
* @param directory to delete contents of
* @param filter if null then no filter is used
* @param recurse will look for contents of sub directories.
* @param deleteEmptyDirectories default is false; if true will delete
* directories found that are empty
* @throws IOException if abstract pathname does not denote a directory, or
* if an I/O error occurs
*/
public static void deleteFilesInDirectory(
final File directory, final FilenameFilter filter,
final boolean recurse, final boolean deleteEmptyDirectories) throws IOException {
// ensure the specified directory is actually a directory and that it exists
if (null != directory && directory.isDirectory()) {
final File ingestFiles[] = directory.listFiles();
if (ingestFiles == null) {
// null if abstract pathname does not denote a directory, or if an I/O error occurs
throw new IOException("Unable to list directory content in: " + directory.getAbsolutePath());
}
for (File ingestFile : ingestFiles) {
boolean process = (filter == null) ? true : filter.accept(directory, ingestFile.getName());
if (ingestFile.isFile() && process) {
FileUtils.deleteFile(ingestFile, 3);
}
if (ingestFile.isDirectory() && recurse) {
FileUtils.deleteFilesInDirectory(ingestFile, filter, recurse, deleteEmptyDirectories);
String[] ingestFileList = ingestFile.list();
if (deleteEmptyDirectories && ingestFileList != null && ingestFileList.length == 0) {
FileUtils.deleteFile(ingestFile, 3);
}
}
}
}
}
/**View on GitHub (pinned to 820761864e)
Solutions
- Verify the process can list the path (ls as the service user).
- Check dmesg/mount status for stale NFS handles and remount the share.
- Re-grant read+execute permission on the directory (readdir needs r and x).
- Ensure no external process deletes/recreates the directory concurrently.
Example fix
// before
FileUtils.deleteFilesInDirectory(dir, filter, true, true);
// after
if (dir != null && dir.canRead()) {
FileUtils.deleteFilesInDirectory(dir, filter, true, true);
} else {
log.warn("skipping cleanup, cannot read {}", dir);
} Defensive patterns
Strategy: retry
Validate before calling
if (directory != null && directory.isDirectory() && !directory.canRead()) {
log.warn("Skipping cleanup: cannot read {}", directory);
return;
} Try / catch
try {
FileUtils.deleteFilesInDirectory(dir, null, true, true);
} catch (IOException e) {
if (e.getMessage().startsWith("Unable to list directory content")) {
// transient IO/race: log and retry later, don't crash the cleanup loop
log.warn("Directory listing failed for {}, will retry next cycle", dir, e);
return;
}
throw e;
} Prevention
- Avoid concurrent deletion/recreation of the same directory by external tooling
- Monitor NFS mounts for stale handles in cleanup jobs
- Keep read+execute permissions on directories subject to automated cleanup
When it happens
Trigger: deleteFilesInDirectory called on a directory that exists (isDirectory() true) but whose entries cannot be enumerated: permission denied on readdir, the directory vanishing mid-scan, or filesystem/IO errors (NFS stale handle).
Common situations: Cleanup tasks for NAR unpack directories racing with external deletion, stale NFS handles after a server restart, or permission changes applied while the process runs.
Related errors
- Failed to read decryption key from ${keyUri}
- ${dir} is not a directory
- ${dir} could not be created
- ${dir} directory does not have read/write privilege
- ${dir} directory does not have read privilege
AI-assisted analysis of apache/pulsar@820761864e (2026-09-06).
Data as JSON: /api/errors/3df6d7c0cd249319.
Report an issue: GitHub.