apache/seatunnel · error · IOException
Unable to open file: ${file}, Aborting
Error message
Unable to open file: ${file}, Aborting What it means
SeaTunnelFTPFileSystem.open() issues RETR via client.retrieveFileStream(); the FSDataInputStream is constructed first, but if the server's reply code is not a positive preliminary (1xx) response, the client is in an inconsistent state. The stream is closed (logging out/disconnecting) and IOException('Unable to open file: <file>, Aborting') is thrown.
Source
Thrown at seatunnel-connectors-v2/connector-file/connector-file-ftp/src/main/java/org/apache/seatunnel/connectors/seatunnel/file/ftp/system/SeaTunnelFTPFileSystem.java:328
throw new FileNotFoundException("Path " + file + " is a directory.");
}
client.allocate(bufferSize);
Path parent = absolute.getParent();
// Change to parent directory on the
// server. Only then can we read the
// file
// on the server by opening up an InputStream. As a side effect the working
// directory on the server is changed to the parent directory of the file.
// The FTP client connection is closed when close() is called on the
// FSDataInputStream.
client.changeWorkingDirectory(parent.toUri().getPath());
InputStream is = client.retrieveFileStream(file.getName());
FSDataInputStream fis = new FSDataInputStream(new FTPInputStream(is, client, statistics));
if (!FTPReply.isPositivePreliminary(client.getReplyCode())) {
// The ftpClient is an inconsistent state. Must close the stream
// which in turn will logout and disconnect from FTP server
fis.close();
throw new IOException("Unable to open file: " + file + ", Aborting");
}
return fis;
}
/**
* A stream obtained via this call must be closed before using other APIs of this class or else
* the invocation will block.
*/
@Override
public FSDataOutputStream create(
Path file,
FsPermission permission,
boolean overwrite,
int bufferSize,
short replication,
long blockSize,
Progressable progress)
throws IOException {View on GitHub (pinned to cf67b549a7)
Solutions
- Check FTP server logs for the RETR reply code to see why the transfer was refused
- Toggle ftp.connection.mode between active and passive to work through the firewall/NAT
- Verify the FTP user has read permission on the file and execute permission on parent directories
- Confirm the file still exists at open time (it may have been deleted or renamed between listing and read)
Example fix
// before "ftp.connection.mode" = "active" // corporate NAT blocks the active data connection // after "ftp.connection.mode" = "passive"
Defensive patterns
Strategy: try-catch
Validate before calling
// Preflight RETR check via a plain FTP client
FTPClient c = connect();
boolean ok = c.retrieveFile(file.getName(), NullOutputStream.INSTANCE);
int reply = c.getReplyCode();
disconnect(c);
if (!ok) throw new IllegalStateException("FTP server refuses RETR for " + file.getName() + ", reply=" + reply); Try / catch
try {
return fs.open(path);
} catch (IOException e) {
if (e.getMessage() != null && e.getMessage().contains("Unable to open file")) {
LOG.warn("RETR failed for {} (reply non-1xx); check perms/firewall/mode", path, e);
// retry with alternate ftp.connection.mode
} else { throw e; }
} Prevention
- Match ftp.connection.mode (active/passive) to your firewall/NAT topology
- Confirm the FTP user can read the file and list its parent directory
- Handle file-discovery-to-open races (file may vanish between list and open)
- Check server logs for the RETR reply code when it fails
When it happens
Trigger: Calling open(file) when the FTP server answers RETR with a non-1xx reply: file not retrievable (permissions, not found at the server side due to changed working directory), server refuses transfer, or data connection cannot be established (firewall blocking passive/active mode).
Common situations: File removed between listing and open; FTP user lacks read permission; firewall/NAT breaks the data channel (common fix: switch ftp.connection.mode between active/passive); server-side transfer restrictions (e.g. TLS required).
Related errors
- Circular condition chain detected: '%s' already exists in th
- Condition for option '%s' has a null operator
- Unable to delete directory " + localFileDir
- WRITER_OPERATION_FAILED
- SeaTunnelAPIErrorCode.CONFIG_VALIDATION_FAILED
AI-assisted analysis of apache/seatunnel@cf67b549a7 (2026-09-10).
Data as JSON: /api/errors/151d0f3f82d49135.
Report an issue: GitHub.