{"record":{"id":"29dcc615b8edbce5","repo":"alibaba/canal","slug":"unable-to-unwrap-to-com-mysql-jdbc-connectionim","errorCode":null,"errorMessage":"Unable to unwrap {} to com.mysql.jdbc.ConnectionImpl","messagePattern":"Unable to unwrap (.+?) to com\\.mysql\\.jdbc\\.ConnectionImpl","errorType":"exception","errorClass":"IOException","httpStatus":null,"severity":"error","filePath":"dbsync/src/main/java/com/taobao/tddl/dbsync/binlog/DirectLogFetcher.java","lineNumber":175,"sourceCode":"\r\n    /**\r\n     * Connect MySQL master to fetch binlog.\r\n     */\r\n    public void open(Connection conn, String fileName, final long filePosition, final int serverId) throws IOException {\r\n        open(conn, fileName, filePosition, serverId, false);\r\n    }\r\n\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","sourceCodeStart":157,"sourceCodeEnd":193,"githubUrl":"https://github.com/alibaba/canal/blob/87be50e87686a3e8af08c368d0e1ffd1f59eb04a/dbsync/src/main/java/com/taobao/tddl/dbsync/binlog/DirectLogFetcher.java#L157-L193","documentation":"Thrown in DirectLogFetcher.open() when unwrapConnection() returns null - i.e. the supplied java.sql.Connection could not be unwrapped (directly, via reflection, or via Wrapper.unwrap) to com.mysql.jdbc.ConnectionImpl. The library needs the raw driver connection to read its private IO streams, so an unwrappable connection is fatal.","triggerScenarios":"open(conn, ...) is called with a Connection that is not, and cannot be unwrapped to, com.mysql.jdbc.ConnectionImpl: a pooling-proxy wrapper, a non-mysql driver, or mysql-connector-java 8.x where ConnectionImpl has been removed in favor of com.mysql.cj.jdbc.JdbcConnection.","commonSituations":"Using HikariCP/DBCP/c3p0 with a delegate that hides the real connection; running against mysql-connector-java 8.x (the legacy com.mysql.jdbc.* package is gone); passing a logical connection from an XA pool; a test/stub connection.","solutions":["Inspect conn.getClass().getName() in the message and confirm it is a real mysql driver connection (or can unwrap to one).","Downgrade to mysql-connector-java 5.1.x which still ships com.mysql.jdbc.ConnectionImpl.","If staying on driver 8.x, switch to a dbsync build that targets com.mysql.cj.jdbc.JdbcConnection, or fetch the binlog over the network protocol instead of via driver reflection.","Configure the pool to expose the underlying connection (e.g. HikariConfig.setAllowPoolSuspension / unwrap the delegate) before passing it to open()."],"exampleFix":"// before - pooled/proxy connection cannot be unwrapped\nfetcher.open(dataSource.getConnection(), file, pos, serverId);\n\n// after - unwrap to the real driver connection first\nConnection raw = dataSource.getConnection();\nif (raw.isWrapperFor(com.mysql.jdbc.Connection.class)) {\n    raw = raw.unwrap(com.mysql.jdbc.Connection.class);\n}\nfetcher.open(raw, file, pos, serverId);","handlingStrategy":"validation","validationCode":"// Ensure the connection can unwrap to the legacy driver class before open\nConnection c = dataSource.getConnection();\nif (c.isWrapperFor(com.mysql.jdbc.Connection.class)) {\n    c = c.unwrap(com.mysql.jdbc.Connection.class);\n} else {\n    throw new IOException(\"connection is not a com.mysql.jdbc.Connection - use connector/j 5.1.x\");\n}","typeGuard":null,"tryCatchPattern":"try { fetcher.open(conn, file, pos, serverId, false); }\ncatch (IOException e) {\n    if (e.getMessage().contains(\"Unable to unwrap\"))\n        throw new IOException(\"need a raw connector/j 5.1.x connection\", e);\n    throw e;\n}","preventionTips":["Use mysql-connector-java 5.1.x which exposes com.mysql.jdbc.ConnectionImpl.","Unwrap pooled connections to the physical driver connection before passing to open().","Do not pass XA/proxy logical connections that hide the underlying driver object."],"tags":["binlog","connection","driver-compat","unwrap","mysql"],"backgroundTag":null,"analyzedSha":"87be50e87686a3e8af08c368d0e1ffd1f59eb04a","analyzedAt":"2026-08-14T04:30:11.918Z","schemaVersion":2},"datasetVersion":"2026-08-14T05:17:29.042Z"}