apache/seatunnel · error · FTPException
Client not connected
Error message
Client not connected
What it means
The FSDataOutputStream returned by create() wraps the FTP storeFileStream; on close(), if the underlying FTPClient is no longer connected it throws FTPException('Client not connected') instead of completing the upload, because the transfer's final status cannot be confirmed.
Source
Thrown at seatunnel-connectors-v2/connector-file/connector-file-ftp/src/main/java/org/apache/seatunnel/connectors/seatunnel/file/ftp/system/SeaTunnelFTPFileSystem.java:384
if (parent == null || !mkdirs(client, parent, FsPermission.getDirDefault())) {
parent = (parent == null) ? new Path("/") : parent;
disconnect(client);
throw new IOException("create(): Mkdirs failed to create: " + parent);
}
client.allocate(bufferSize);
// Change to parent directory on the server. Only then can we write to the
// file on the server by opening up an OutputStream. 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
// FSDataOutputStream.
client.changeWorkingDirectory(parent.toUri().getPath());
FSDataOutputStream fos =
new FSDataOutputStream(client.storeFileStream(file.getName()), statistics) {
@Override
public void close() throws IOException {
super.close();
if (!client.isConnected()) {
throw new FTPException("Client not connected");
}
boolean cmdCompleted = client.completePendingCommand();
disconnect(client);
if (!cmdCompleted) {
throw new FTPException(
"Could not complete transfer, Reply Code - "
+ client.getReplyCode());
}
}
};
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
fos.close();
throw new IOException("Unable to create file: " + file + ", Aborting");
}
return fos;
}View on GitHub (pinned to cf67b549a7)
Solutions
- Investigate why the control connection dropped (server idle timeout, firewall, server restart) and adjust server-side timeouts
- Write data continuously or use smaller files so the connection does not idle out mid-transfer
- Enable FTP keep-alive if available and confirm the client host is not NAT-idled; retry the whole upload on a fresh connection
- Check FTP server logs around the failure time for the disconnect cause
Example fix
// before // long client-side pause between writes -> server times out control connection // after // stream data promptly; wrap upload in retry with fresh create() on IOException/FTPException
Defensive patterns
Strategy: try-catch
Validate before calling
// Monitor control-connection health before/during long uploads
FTPClient c = connect();
if (!c.isConnected() || c.getReplyCode() == 421) {
throw new IllegalStateException("FTP control connection unhealthy before upload");
} Try / catch
try (FSDataOutputStream out = fs.create(path, true)) {
out.write(data); // write promptly, avoid long idle gaps
} catch (FTPException | IOException e) {
if (e.getMessage() != null && e.getMessage().contains("Client not connected")) {
// retry whole upload on a fresh connection
retryUpload(path, data);
} else { throw e; }
} Prevention
- Raise the server's idle control-connection timeout for large uploads
- Avoid long client-side pauses between writes; buffer locally and stream continuously
- Retry uploads from scratch on a fresh connection after any drop
- Check for firewalls/NAT that kill idle TCP sessions mid-transfer
When it happens
Trigger: Closing the output stream after the FTP control connection dropped — server-side idle timeout, network interruption, server restarting, or the connection killed by a firewall during the write.
Common situations: Long pauses while writing a large file causing the FTP server to time out the idle control connection; unstable network between client and server; server-enforced connection limits dropping the session.
Related errors
- Server response ${reply}
- CREATE_ACTIVEMQ_CLIENT_FAILED
- CONNECTION_FAILED
- CONNECTION_FAILED
- Timed out after <actualSeconds> seconds while waiting to con
AI-assisted analysis of apache/seatunnel@cf67b549a7 (2026-09-10).
Data as JSON: /api/errors/88cc6807057919bd.
Report an issue: GitHub.