apache/hadoop · error · FTPException
Client not connected
Error message
Client not connected
What it means
close() first delegates to super.close(), sets closed=true, and only then verifies client.isConnected(); if the FTP control connection is already gone it throws FTPException("Client not connected"). By then the stream is closed and the client unusable, so the transfer's completeness must be verified independently.
Source
Thrown at hadoop-common-project/hadoop-common/src/main/java/org/apache/hadoop/fs/ftp/FTPInputStream.java:111
if (result > 0) {
pos += result;
}
if (stats != null && result > 0) {
stats.incrementBytesRead(result);
}
return result;
}
@Override
public synchronized void close() throws IOException {
if (closed) {
return;
}
super.close();
closed = true;
if (!client.isConnected()) {
throw new FTPException("Client not connected");
}
boolean cmdCompleted = client.completePendingCommand();
client.logout();
client.disconnect();
if (!cmdCompleted) {
throw new FTPException("Could not complete transfer, Reply Code - "
+ client.getReplyCode());
}
}
// Not supported.
@Override
public boolean markSupported() {
return false;
}
View on GitHub (pinned to 2add963021)
Solutions
- Catch FTPException from close() separately and decide success by data completeness: compare bytes consumed (getPos()) with getFileStatus().getLen()
- Enable control-channel keepalive so long transfers keep the control session alive
- Do not double-manage the client — let the stream own logout/disconnect
- If completeness cannot be proven, reopen and re-read from the last known position
Example fix
// before
in.close(); // FTPException("Client not connected")
// after
try {
in.close();
} catch (FTPException e) {
boolean complete = in.getPos() == fs.getFileStatus(path).getLen();
if (!complete) {
throw e; // truncated transfer -> real failure
}
LOG.warn("control connection gone at close; data complete", e);
} Defensive patterns
Strategy: try-catch
Try / catch
wrap close() in its own try/catch for FTPException; on "Client not connected" decide via getPos() == file length whether the data is complete — complete means benign, truncated means reopen and re-read.
Prevention
- Enable control-channel keepalive for long transfers
- Let the stream own logout/disconnect; never disconnect its client elsewhere first
- Verify read completeness with position-vs-length after every transfer
When it happens
Trigger: Server-side idle/session timeout dropped the control connection before close() was called; network reset mid-transfer; close() racing another thread that already logged out/disconnected the shared FTP client.
Common situations: Long downloads exceeding server idle limits; NAT/firewall tearing down control sessions during big transfers; calling close() after FTPFileSystem logic already disconnected the connection the stream was using.
Related errors
- Failed to get home directory
- Could not complete transfer, Reply Code -
- Failed to delete temporary files while closing stream: '%s'
- File check failed
- Source path {src} does not exist
AI-assisted analysis of apache/hadoop@2add963021 (2026-08-22).
Data as JSON: /api/errors/f23de41ab9ce325e.
Report an issue: GitHub.