{"record":{"id":"222c0517726e9056","repo":"apache/seatunnel","slug":"iotdbconnectorerrorcode-close-client-failed","errorCode":"IotdbConnectorErrorCode.CLOSE_CLIENT_FAILED","errorMessage":"Close IoTDB client failed.","messagePattern":"Close IoTDB client failed\\.","errorType":"error_code","errorClass":"IotdbConnectorException","httpStatus":null,"severity":"warning","filePath":"seatunnel-connectors-v2/connector-iotdb/src/main/java/org/apache/seatunnel/connectors/seatunnel/iotdb/sink/IoTDBSinkClient.java","lineNumber":113,"sourceCode":"        tryInit();\n        checkFlushException();\n\n        batchList.add(record);\n        if (sinkConfig.getBatchSize() > 0 && batchList.size() >= sinkConfig.getBatchSize()) {\n            flush();\n        }\n    }\n\n    public synchronized void close() throws IOException {\n        flush();\n\n        try {\n            if (session != null) {\n                session.close();\n            }\n        } catch (IoTDBConnectionException e) {\n            log.error(\"Close IoTDB client failed.\", e);\n            throw new IotdbConnectorException(\n                    IotdbConnectorErrorCode.CLOSE_CLIENT_FAILED, \"Close IoTDB client failed.\", e);\n        }\n    }\n\n    synchronized void flush() throws IOException {\n        checkFlushException();\n        if (batchList.isEmpty()) {\n            return;\n        }\n\n        BatchRecords batchRecords = new BatchRecords(batchList);\n        for (int i = 0; i <= sinkConfig.getMaxRetries(); i++) {\n            try {\n                if (batchRecords.getTypesList().isEmpty()) {\n                    session.insertRecords(\n                            batchRecords.getDeviceIds(),\n                            batchRecords.getTimestamps(),\n                            batchRecords.getMeasurementsList(),","sourceCodeStart":95,"sourceCodeEnd":131,"githubUrl":"https://github.com/apache/seatunnel/blob/cf67b549a7a6c35fa0beb12d83c62892427ea919/seatunnel-connectors-v2/connector-iotdb/src/main/java/org/apache/seatunnel/connectors/seatunnel/iotdb/sink/IoTDBSinkClient.java#L95-L131","documentation":"IoTDBSinkClient.close() closes the IoTDB Session when the writer is being released; if session.close() throws IoTDBConnectionException it rethrows CLOSE_CLIENT_FAILED. Like the source-side session-close error, it signals the connection was already dead or the server rejected the close, not a logic error in close().","triggerScenarios":"close() invoked at end-of-task/checkpoint while session != null and session.close() raises IoTDBConnectionException — server restarted mid-job, session timed out, network dropped, or session already closed.","commonSituations":"Long-running sink job whose idle TCP connection was dropped by a firewall; IoTDB DataNode restarted during the job; double-close after a prior failure path already terminated the session.","solutions":["Check the wrapped IoTDBConnectionException cause and IoTDB server logs for the connection state at close time","Ensure flush() is called successfully before close so pending data is not lost (data loss, not close, is the real risk)","Keep the connection alive for long jobs (TCP keepalive, avoid long idle periods between batches)","If transient, treat as a job-level failure and rerun; verify network stability between SeaTunnel worker and IoTDB"],"exampleFix":"// before\npublic void close() throws IOException {\n    try {\n        if (session != null) {\n            session.close();\n        }\n    } catch (IoTDBConnectionException e) {\n        throw new IotdbConnectorException(IotdbConnectorErrorCode.CLOSE_CLIENT_FAILED, \"Close IoTDB client failed.\", e);\n    }\n}\n// after\npublic void close() throws IOException {\n    try {\n        flush();\n    } finally {\n        try {\n            if (session != null) {\n                session.close();\n            }\n        } catch (IoTDBConnectionException e) {\n            log.warn(\"Session already closed/broken: {}\", e.getMessage());\n            throw new IotdbConnectorException(IotdbConnectorErrorCode.CLOSE_CLIENT_FAILED, \"Close IoTDB client failed.\", e);\n        }\n    }\n}","handlingStrategy":"try-catch","validationCode":null,"typeGuard":"boolean sessionAlive(IoTDBSinkClient client) { return client != null; }","tryCatchPattern":"try {\n    sinkWriter.close();\n} catch (IotdbConnectorException e) {\n    if (e.getCode() == IotdbConnectorErrorCode.CLOSE_CLIENT_FAILED) {\n        log.warn(\"IoTDB session close failed (connection likely already broken): {}\", e.getCause());\n    } else { throw e; }\n}","preventionTips":["Flush all pending data before close so a dead session at close time does not lose records","Enable TCP keepalive / avoid long idle gaps between write batches","Monitor IoTDB DataNode restarts during job runtime"],"tags":["iotdb","session-close","sink","network"],"backgroundTag":"connection-refused","analyzedSha":"cf67b549a7a6c35fa0beb12d83c62892427ea919","analyzedAt":"2026-09-10T21:44:55.265Z","contentChangedAt":"2026-09-10T21:44:55.265Z","schemaVersion":2},"datasetVersion":"2026-09-14T11:17:12.474Z"}