apache/hadoop · error · FTPException
Could not complete transfer, Reply Code -
Error message
Could not complete transfer, Reply Code -
What it means
In close(), after the data stream ends the client must call completePendingCommand() to read the server's final reply; false means the server never confirmed success (e.g. 4xx/5xx or aborted transfer). The code then logs out, disconnects, and throws FTPException("Could not complete transfer, Reply Code - N"). The reply code is fetched after disconnect(), so treat it as the last known code and verify transfer completeness independently.
Source
Thrown at hadoop-common-project/hadoop-common/src/main/java/org/apache/hadoop/fs/ftp/FTPInputStream.java:118
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;
}
@Override
public void mark(int readLimit) {
// Do nothing
}
@Override
public void reset() throws IOException {View on GitHub (pinned to 2add963021)
Solutions
- Match the reply code with the FTP server log entry to find the true 4xx/5xx reason
- Verify the passive-mode port range is open end-to-end or switch active/passive mode to suit the network
- Validate size after read: compare bytes consumed (getPos()) with the file length from getFileStatus()
- Retry the full open/read/close cycle once — transient data-channel failures are common
Example fix
// before
try (FSDataInputStream in = fs.open(path)) {
IOUtils.copyBytes(in, out, conf); // close() may throw "Could not complete transfer"
}
// after
try (FSDataInputStream in = fs.open(path)) {
IOUtils.copyBytes(in, out, conf);
long read = in.getPos();
long expected = fs.getFileStatus(path).getLen();
if (read != expected) {
throw new IOException("short read: " + read + " of " + expected);
}
} Defensive patterns
Strategy: retry
Validate before calling
// verify completeness before trusting a completed copy
long read = in.getPos();
long expected = fs.getFileStatus(path).getLen();
if (read != expected) { /* treat as truncated; plan resume */ } Try / catch
catch FTPException from close(); when the message starts with "Could not complete transfer", record getPos() as the resume point, reopen the stream, skip to that point, and continue reading — retry the whole cycle once before failing.
Prevention
- Keep the passive data port range open through every firewall on the path
- Always compare consumed bytes with the advertised file length
- Capture the server-side reply string in logs for diagnosis
When it happens
Trigger: Data connection breaking mid-RETR (passive port blocked, NAT timeout); server returning 426/550 during streaming; the reader closing early and abandoning the transfer; local disk/network errors aborting the download.
Common situations: Firewalls allowing control port 21 but blocking the passive data port range; large transfers hitting NAT idle timeouts; quota or permission changes on the server mid-session.
Related errors
- Client not connected
- Failed to delete temporary files while closing stream: '%s'
- Unable to open file: {file}, Aborting
- Unable to create file: {file}, Aborting
- File check failed
AI-assisted analysis of apache/hadoop@2add963021 (2026-08-22).
Data as JSON: /api/errors/65760d090d7c14b8.
Report an issue: GitHub.