{"record":{"id":"263d4b5b40ffc652","repo":"apache/seatunnel","slug":"failed-to-disconnect-from-ftp-server","errorCode":null,"errorMessage":"Failed to disconnect from FTP server","messagePattern":"Failed to disconnect from FTP server","errorType":"console","errorClass":null,"httpStatus":null,"severity":"warning","filePath":"seatunnel-connectors-v2/connector-file/connector-file-ftp/src/main/java/org/apache/seatunnel/connectors/seatunnel/file/ftp/system/SeaTunnelFTPFileSystem.java","lineNumber":274,"sourceCode":"        }\n\n        try {\n            boolean logoutSuccess = client.logout();\n            if (!logoutSuccess) {\n                LOG.warn(\n                        \"Logout failed while disconnecting, error code - \" + client.getReplyCode());\n            }\n        } catch (IOException e) {\n            // Some FTP servers close the control connection before responding to QUIT. The\n            // preceding operation has already completed, so do not turn a successful operation\n            // into a failure while releasing the connection.\n            LOG.warn(\"Failed to logout from FTP server while disconnecting\", e);\n        } finally {\n            if (client.isConnected()) {\n                try {\n                    client.disconnect();\n                } catch (IOException e) {\n                    LOG.warn(\"Failed to disconnect from FTP server\", e);\n                }\n            }\n        }\n    }\n\n    /**\n     * Resolve against given working directory. *\n     *\n     * @param workDir workDir\n     * @param path path\n     * @return Path\n     */\n    private Path makeAbsolute(Path workDir, Path path) {\n        if (path.isAbsolute()) {\n            String filePath = path.toUri().getPath();\n            if (filePath.equals(\"/\")) {\n                return workDir;\n            }","sourceCodeStart":256,"sourceCodeEnd":292,"githubUrl":"https://github.com/apache/seatunnel/blob/cf67b549a7a6c35fa0beb12d83c62892427ea919/seatunnel-connectors-v2/connector-file/connector-file-ftp/src/main/java/org/apache/seatunnel/connectors/seatunnel/file/ftp/system/SeaTunnelFTPFileSystem.java#L256-L292","documentation":"In disconnect()'s finally block, the physical disconnect() call on a still-connected FTPClient threw an IOException. Like the logout warning, this is swallowed and logged at WARN because the session is being discarded anyway; the connection release cannot fail the enclosing operation.","triggerScenarios":"client.isConnected() is still true in the finally block after logout failed, and the subsequent client.disconnect() raises IOException — e.g. the socket is already half-closed by the server, a reset (RST) arrives, or the underlying socket is in an inconsistent state.","commonSituations":"Server forcefully reset the connection (connection reset) before the client could close it; half-open TCP connection after a network drop; double-close races in pooled/reused clients; FTP server crash during session teardown.","solutions":["No action needed — the exception is intentionally logged at WARN; the connection object is abandoned afterward and garbage collected.","If sockets accumulate (fd leak), confirm this is the only disconnect path and check whether clients are shared across threads.","Investigate network middleboxes (NAT/firewall) that may be dropping idle control connections abruptly; enable keep-alive or reduce session idle time."],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"// Same swallow-and-log pattern the connector uses:\nif (client.isConnected()) {\n    try {\n        client.disconnect();\n    } catch (IOException e) {\n        LOG.warn(\"Failed to disconnect from FTP server (non-fatal)\", e);\n    }\n}","preventionTips":["Never reuse an FTPClient after a failed disconnect — create a fresh one","Check for NAT/firewall devices that reset idle control connections","If socket/file-descriptor leaks appear, ensure every client passes through disconnect() in a finally block"],"tags":["ftp","disconnect","socket","teardown"],"backgroundTag":"broken-pipe","analyzedSha":"cf67b549a7a6c35fa0beb12d83c62892427ea919","analyzedAt":"2026-09-10T21:44:55.265Z","contentChangedAt":"2026-09-10T21:44:55.265Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}