{"record":{"id":"f23de41ab9ce325e","repo":"apache/hadoop","slug":"client-not-connected-f23de4","errorCode":null,"errorMessage":"Client not connected","messagePattern":"Client not connected","errorType":"exception","errorClass":"FTPException","httpStatus":null,"severity":"error","filePath":"hadoop-common-project/hadoop-common/src/main/java/org/apache/hadoop/fs/ftp/FTPInputStream.java","lineNumber":111,"sourceCode":"    if (result > 0) {\n      pos += result;\n    }\n    if (stats != null && result > 0) {\n      stats.incrementBytesRead(result);\n    }\n\n    return result;\n  }\n\n  @Override\n  public synchronized void close() throws IOException {\n    if (closed) {\n      return;\n    }\n    super.close();\n    closed = true;\n    if (!client.isConnected()) {\n      throw new FTPException(\"Client not connected\");\n    }\n\n    boolean cmdCompleted = client.completePendingCommand();\n    client.logout();\n    client.disconnect();\n    if (!cmdCompleted) {\n      throw new FTPException(\"Could not complete transfer, Reply Code - \"\n          + client.getReplyCode());\n    }\n  }\n\n  // Not supported.\n\n  @Override\n  public boolean markSupported() {\n    return false;\n  }\n","sourceCodeStart":93,"sourceCodeEnd":129,"githubUrl":"https://github.com/apache/hadoop/blob/2add9630210752f88ceb1bb74eb65e37bf41da8e/hadoop-common-project/hadoop-common/src/main/java/org/apache/hadoop/fs/ftp/FTPInputStream.java#L93-L129","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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"],"exampleFix":"// before\nin.close();                      // FTPException(\"Client not connected\")\n\n// after\ntry {\n  in.close();\n} catch (FTPException e) {\n  boolean complete = in.getPos() == fs.getFileStatus(path).getLen();\n  if (!complete) {\n    throw e;                     // truncated transfer -> real failure\n  }\n  LOG.warn(\"control connection gone at close; data complete\", e);\n}","handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"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.","preventionTips":["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"],"tags":["ftp","hadoop","close","connection"],"backgroundTag":"ftp-client-disconnected","analyzedSha":"2add9630210752f88ceb1bb74eb65e37bf41da8e","analyzedAt":"2026-08-22T19:55:07.957Z","schemaVersion":2},"datasetVersion":"2026-08-23T01:17:44.959Z"}