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

  1. Catch FTPException from close() separately and decide success by data completeness: compare bytes consumed (getPos()) with getFileStatus().getLen()
  2. Enable control-channel keepalive so long transfers keep the control session alive
  3. Do not double-manage the client — let the stream own logout/disconnect
  4. 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

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


AI-assisted analysis of apache/hadoop@2add963021 (2026-08-22). Data as JSON: /api/errors/f23de41ab9ce325e. Report an issue: GitHub.