apache/seatunnel · error · FTPException

Could not complete transfer, Reply Code - ${client.getReplyC

Error message

Could not complete transfer, Reply Code - ${client.getReplyCode()}

What it means

Thrown by SeaTunnelFTPFileSystem when closing an FTP output stream: the FTP client sent the write commands, but the server did not report a successful completion of the pending data transfer. It means the file content may not have been fully persisted on the FTP server, so the filesystem throws rather than silently reporting success on a truncated or failed upload.

Source

Thrown at seatunnel-connectors-v2/connector-file/connector-file-ftp/src/main/java/org/apache/seatunnel/connectors/seatunnel/file/ftp/system/SeaTunnelFTPFileSystem.java:389

        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;
    }

    /** This optional operation is not yet supported. */
    @Override
    public FSDataOutputStream append(Path f, int bufferSize, Progressable progress)
            throws IOException {

View on GitHub (pinned to cf67b549a7)

Solutions

  1. Check the FTP server logs and disk space/quota for the target directory
  2. Verify the FTP user has write permission on the target file path
  3. Configure passive mode (and correct port range in the firewall) to keep the data channel alive
  4. Increase connection/idle timeouts and retry the whole write operation
  5. Check client.getReplyCode() in server logs (e.g. 452/553) to identify the server-side rejection

Example fix

// before
try (FSDataOutputStream out = fs.create(path)) {
    out.write(bigBuffer);
}
// after
try (FSDataOutputStream out = fs.create(path)) {
    out.write(chunk);
    out.flush(); // flush periodically to surface transfer errors early
}
// and retry the entire write on failure instead of assuming partial success
Defensive patterns

Strategy: try-catch

Validate before calling

// pre-flight: check server reachability and target writability
if (!fs.exists(path.getParent())) throw new IllegalStateException("parent dir missing");

Type guard

// Java: no dynamic type guard; guard state instead
boolean safeToWrite(FTPClient client) { return client != null && client.isConnected(); }

Try / catch

try (FSDataOutputStream out = fs.create(path)) {
    out.write(data);
} catch (IOException e) {
    if (e.getMessage().contains("Could not complete transfer")) {
        // treat file as corrupt: delete partial file and retry whole write
        fs.delete(path, false);
    }
    throw e;
}

Prevention

When it happens

Trigger: Closing the FSDataOutputStream returned by create() when client.completePendingCommand() returns false — typically caused by the server rejecting or aborting the STOR transfer (disk full, permission denied on target file, connection dropped mid-transfer, server-enforced quota).

Common situations: Uploading to an FTP server whose disk is full or whose user quota is exceeded; network interruption during a large file write; FTP server configured with file size limits; passive-mode/firewall issues that drop the data channel; writing to a directory where the user lacks write permission after the initial file creation handshake succeeded.

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


AI-assisted analysis of apache/seatunnel@cf67b549a7 (2026-09-10). Data as JSON: /api/errors/042fdcae47370c5e. Report an issue: GitHub.