{"record":{"id":"ace3823313ec395a","repo":"alibaba/canal","slug":"get-null-field-io","errorCode":null,"errorMessage":"Get null field:{}#io","messagePattern":"Get null field:(.+?)#io","errorType":"exception","errorClass":"IOException","httpStatus":null,"severity":"error","filePath":"dbsync/src/main/java/com/taobao/tddl/dbsync/binlog/DirectLogFetcher.java","lineNumber":182,"sourceCode":"\r\n    /**\r\n     * Connect MySQL master to fetch binlog.\r\n     */\r\n    public void open(Connection conn, String fileName, long filePosition, final int serverId, boolean nonBlocking)\r\n                                                                                                                  throws IOException {\r\n        try {\r\n            this.conn = conn;\r\n            Class<?> connClazz = Class.forName(\"com.mysql.jdbc.ConnectionImpl\");\r\n            Object unwrapConn = unwrapConnection(conn, connClazz);\r\n            if (unwrapConn == null) {\r\n                throw new IOException(\"Unable to unwrap \" + conn.getClass().getName()\r\n                                      + \" to com.mysql.jdbc.ConnectionImpl\");\r\n            }\r\n\r\n            // Get underlying IO streams for network communications.\r\n            Object connIo = getDeclaredField(unwrapConn, connClazz, \"io\");\r\n            if (connIo == null) {\r\n                throw new IOException(\"Get null field:\" + conn.getClass().getName() + \"#io\");\r\n            }\r\n            mysqlOutput = (OutputStream) getDeclaredField(connIo, connIo.getClass(), \"mysqlOutput\");\r\n            mysqlInput = (InputStream) getDeclaredField(connIo, connIo.getClass(), \"mysqlInput\");\r\n\r\n            if (filePosition == 0) filePosition = BIN_LOG_HEADER_SIZE;\r\n            sendBinlogDump(fileName, filePosition, serverId, nonBlocking);\r\n            position = 0;\r\n        } catch (IOException e) {\r\n            close(); /* Do cleanup */\r\n            logger.error(\"Error on COM_BINLOG_DUMP: file = \" + fileName + \", position = \" + filePosition);\r\n            throw e;\r\n        } catch (ClassNotFoundException e) {\r\n            close(); /* Do cleanup */\r\n            throw new IOException(\"Unable to load com.mysql.jdbc.ConnectionImpl\", e);\r\n        }\r\n    }\r\n\r\n    /**\r","sourceCodeStart":164,"sourceCodeEnd":200,"githubUrl":"https://github.com/alibaba/canal/blob/87be50e87686a3e8af08c368d0e1ffd1f59eb04a/dbsync/src/main/java/com/taobao/tddl/dbsync/binlog/DirectLogFetcher.java#L164-L200","documentation":"Thrown in DirectLogFetcher.open() after successfully reading the 'io' field off the unwrapped ConnectionImpl: the field exists but holds null. The connection's internal MysqlIO object is null, meaning the connection is not (or no longer) in an initialized/connected state.","triggerScenarios":"getDeclaredField(unwrapConn, ConnectionImpl.class, \"io\") returns null - the connection object is a closed, half-constructed, or already-disconnected instance whose IO channel has been torn down.","commonSituations":"The connection was closed (explicit close or pool eviction) before open(); a prior error left the connection in a broken state; the pool handed back a stub; the connection was created but never fully connected to the master.","solutions":["Validate the connection is usable (Connection.isValid(timeout) or a SELECT 1) before passing it to open().","Obtain a fresh connection from the pool/driver immediately before open() rather than reusing a cached/closed one.","Check logs for an earlier close/disconnect on the same connection object.","Ensure the connection is not auto-evicted by the pool while replication is active (increase idle/leak thresholds)."],"exampleFix":"// before\nfetcher.open(conn, file, pos, serverId); // conn may be closed -> io == null\n\n// after - verify liveness first\nif (conn == null || conn.isClosed() || !conn.isValid(2)) {\n    throw new IOException(\"Refusing to open fetcher on a dead connection\");\n}\nfetcher.open(conn, file, pos, serverId);","handlingStrategy":"validation","validationCode":"// Reject dead connections before the fetcher reflects on them\nif (conn == null || conn.isClosed() || !conn.isValid(2)) {\n    throw new IOException(\"refusing to open fetcher on a non-live connection\");\n}","typeGuard":null,"tryCatchPattern":"try { fetcher.open(conn, file, pos, serverId, false); }\ncatch (IOException e) {\n    if (e.getMessage().contains(\"Get null field\") && e.getMessage().contains(\"#io\"))\n        logger.error(\"connection 'io' is null - connection was closed/invalid\", e);\n    throw e;\n}","preventionTips":["Call Connection.isValid() or a SELECT 1 before open().","Pull a fresh connection immediately before opening the fetcher.","Keep the connection alive for the duration of replication (raise pool idle/leak limits)."],"tags":["binlog","connection","driver-compat","mysql"],"backgroundTag":null,"analyzedSha":"87be50e87686a3e8af08c368d0e1ffd1f59eb04a","analyzedAt":"2026-08-14T04:30:11.918Z","schemaVersion":2},"datasetVersion":"2026-08-14T05:17:29.042Z"}