apache/seatunnel · error · IOException
Directory: %s is not empty.
Error message
Directory: %s is not empty.
What it means
delete() refuses to remove a directory that still contains entries when recursive=false, throwing IOException formatted with E_DIR_NOTEMPTY. This mirrors Hadoop FileSystem semantics: non-recursive deletes of non-empty directories are rejected rather than silently truncating data.
Source
Thrown at seatunnel-connectors-v2/connector-file/connector-file-sftp/src/main/java/org/apache/seatunnel/connectors/seatunnel/file/sftp/system/SFTPFileSystem.java:383
fileStat = getFileStatus(channel, absolute);
} catch (FileNotFoundException e) {
// file not found, no need to delete, return true
return false;
}
if (!fileStat.isDirectory()) {
boolean status = true;
try {
channel.rm(pathName);
} catch (SftpException e) {
status = false;
}
return status;
} else {
boolean status = true;
FileStatus[] dirEntries = listStatus(channel, absolute);
if (dirEntries != null && dirEntries.length > 0) {
if (!recursive) {
throw new IOException(String.format(E_DIR_NOTEMPTY, file));
}
for (int i = 0; i < dirEntries.length; ++i) {
delete(channel, new Path(absolute, dirEntries[i].getPath()), recursive);
}
}
try {
channel.rmdir(pathName);
} catch (SftpException e) {
status = false;
}
return status;
}
}
/**
* Convenience method, so that we don't open a new connection when using this method from within
* another method. Otherwise every API invocation incurs the overhead of opening/closing a TCP
* connection.View on GitHub (pinned to cf67b549a7)
Solutions
- Pass recursive=true: fs.delete(path, true)
- Empty the directory first (delete each child) then delete the directory
- Pick a fresh output path or enable overwrite-aware cleanup before the job
- Verify the directory is actually empty (fs.listStatus(path).length == 0) before a non-recursive delete
Example fix
// before
fs.delete(new Path("/tmp/out"), false);
// after
fs.delete(new Path("/tmp/out"), true); Defensive patterns
Strategy: validation
Validate before calling
Path dir = new Path("/tmp/out");
if (fs.exists(dir) && fs.getFileStatus(dir).isDirectory()
&& fs.listStatus(dir).length > 0 && !recursive) {
throw new IllegalStateException("Refusing non-recursive delete of non-empty " + dir);
} Try / catch
try {
fs.delete(dir, false);
} catch (IOException e) {
if (String.valueOf(e.getMessage()).contains("is not empty")) {
fs.delete(dir, true); // escalate to recursive
} else { throw e; }
} Prevention
- Always pass an explicit recursive flag matching intent
- Clean output directories before job start
- Make deletes idempotent in retry logic
When it happens
Trigger: fs.delete(dirPath, false) on a directory that contains at least one file or subdirectory (as reported by listStatus).
Common situations: Cleanup code assuming delete() clears whole trees but passing recursive=false; overwriting an existing non-empty output directory during job setup; leftover files from a previous failed run.
Related errors
- SftpException wrapped (ls failed while listing status)
- ACKNOWLEDGE_FAILED
- Directory: ${file} is not empty.
- Can't make directory for path %s since it is a file.
- SFTP connection pool has been closed.
AI-assisted analysis of apache/seatunnel@cf67b549a7 (2026-09-10).
Data as JSON: /api/errors/a4b9f2e4f0935db9.
Report an issue: GitHub.