apache/seatunnel · error · IOException
Failed to create directory %s in %s, FTP reply code: %d, rep
Error message
Failed to create directory %s in %s, FTP reply code: %d, reply string: %s
What it means
SeaTunnelFTPFileSystem wraps Apache Commons Net FTPClient to provide HDFS-like filesystem semantics over FTP. When creating a directory via makeDirectory, an FTP server may return false even though the code intends success; the code double-checks existence and throws this IOException with the raw FTP reply code and string so the operator can diagnose the server-side rejection.
Source
Thrown at seatunnel-connectors-v2/connector-file/connector-file-ftp/src/main/java/org/apache/seatunnel/connectors/seatunnel/file/ftp/system/SeaTunnelFTPFileSystem.java:758
}
// Create the directory
String pathName = absolute.getName();
String parentDir = parent != null ? parent.toUri().getPath() : "/";
// Change to parent directory
if (!client.changeWorkingDirectory(parentDir)) {
throw new IOException(
String.format(
"Failed to change working directory to %s, FTP reply code: %d, reply string: %s",
parentDir, client.getReplyCode(), client.getReplyString()));
}
// Create directory
boolean created = client.makeDirectory(pathName);
if (!created) {
// Double check if directory was actually created (some FTP servers don't return true)
if (!exists(client, absolute)) {
throw new IOException(
String.format(
"Failed to create directory %s in %s, FTP reply code: %d, reply string: %s",
pathName,
parentDir,
client.getReplyCode(),
client.getReplyString()));
}
}
return true;
}
/**
* 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.
*/
private boolean isFile(FTPClient client, Path file) {
try {View on GitHub (pinned to cf67b549a7)
Solutions
- Check the FTP reply code in the message: 550 usually means permission denied or file exists — verify the FTP user has write permission on the parent directory
- Ensure the parent directory exists before writing; create parent directories first
- Verify the path is absolute and correct relative to the FTP user's home directory (FTP servers resolve relative paths against the login dir)
- Connect to the FTP server manually (ftp/lftp) and run MKD on the same path to see the raw server reply
- Check server disk quota / filesystem full on the FTP host
Example fix
// before
boolean created = client.makeDirectory("data/output"); // relative path, may resolve unexpectedly
// after
String absolutePath = "/home/ftpuser/data/output";
client.changeWorkingDirectory("/");
for (String part : absolutePath.split("/")) {
if (!part.isEmpty() && !client.makeDirectory(part) && !client.changeWorkingDirectory(part)) {
throw new IOException("Cannot create or enter " + part + ": " + client.getReplyString());
}
} Defensive patterns
Strategy: validation
Validate before calling
// Java: pre-check FTP write access before job run
FTPClient c = new FTPClient();
c.connect(host, port);
c.login(user, pass);
String dir = path.substring(0, path.lastIndexOf('/'));
if (!c.changeWorkingDirectory(dir)) {
throw new IllegalStateException("Cannot access FTP dir " + dir + ": " + c.getReplyString());
}
c.disconnect(); Type guard
// Java
static boolean canWriteToFtpDir(FTPClient client, String dir) throws IOException {
return client.changeWorkingDirectory(dir) && FTPReply.isPositiveCompletion(client.getReplyCode());
} Try / catch
try {
ftpFileSystem.mkdir(path);
} catch (IOException e) {
logger.error("FTP mkdir failed (check reply code in message, likely permission/missing parent): {}", path, e);
throw new RuntimeException("FTP directory creation failed for " + path, e);
} Prevention
- Verify FTP user write permissions on the target directory with a manual MKD test before configuring jobs
- Use absolute paths starting with '/' to avoid working-directory resolution surprises
- Create parent directories explicitly rather than relying on recursive creation
- Monitor FTP server quota and disk space
When it happens
Trigger: client.makeDirectory(pathName) returns false AND a subsequent exists(client, absolute) check confirms the directory was not created; the IOException is thrown at SeaTunnelFTPFileSystem.java:758 with client.getReplyCode()/getReplyString() embedded.
Common situations: FTP user lacks write permission on the parent directory; parent directory itself does not exist (some servers refuse nested creation); server in a read-only or quota-exceeded state; path violates server-side naming rules; relative path resolved against an unexpected working directory.
Understand the failure class
Background: "failed to write file", "Could not save figure", "Error saving remote file" — file write failed: causes and fixes across languages and libraries — this error's family across 38 libraries.
Related errors
- Unable to open file: ${file}, Aborting
- Unable to create file: ${file}, Aborting
- Directory: ${file} is not empty.
- File check failed
- Circular condition chain detected: '%s' already exists in th
AI-assisted analysis of apache/seatunnel@cf67b549a7 (2026-09-10).
Data as JSON: /api/errors/761d5cffc8dfd903.
Report an issue: GitHub.