{"record":{"id":"77fd77bb34cc8283","repo":"alibaba/canal","slug":"errno-sqlstate-errmsg","errorCode":null,"errorMessage":" errno = {}, sqlstate = {} errmsg = {}","messagePattern":" errno = (.+?), sqlstate = (.+?) errmsg = (.+?)","errorType":"exception","errorClass":"ServerLogPurgedException","httpStatus":null,"severity":"critical","filePath":"parse/src/main/java/com/alibaba/otter/canal/parse/inbound/mysql/dbsync/DirectLogFetcher.java","lineNumber":107,"sourceCode":"                return false;\n            }\n\n            // Detecting error code.\n            final int mark = getUint8(NET_HEADER_SIZE);\n            if (mark != 0) {\n                if (mark == 255) // error from master\n                {\n                    // Indicates an error, for example trying to fetch from\n                    // wrong\n                    // binlog position.\n                    position = NET_HEADER_SIZE + 1;\n                    final int errno = getInt16();\n                    String sqlstate = forward(1).getFixString(SQLSTATE_LENGTH);\n                    String errmsg = getFixString(limit - position);\n                    if (StringUtils.containsIgnoreCase(errmsg, \"not find first log file name\")\n                        || StringUtils.containsIgnoreCase(errmsg, \"purged binary logs\")) {\n                        // 开始 dump 后，server 位点过期，DUMP 和 DUMP_GTID 两种错误信息\n                        throw new ServerLogPurgedException(\n                            \" errno = \" + errno + \", sqlstate = \" + sqlstate + \" errmsg = \" + errmsg);\n                    }\n\n                    throw new IOException(\"Received error packet:\" + \" errno = \" + errno + \", sqlstate = \" + sqlstate\n                                          + \" errmsg = \" + errmsg);\n                } else if (mark == 254) {\n                    // Indicates end of stream. It's not clear when this would\n                    // be sent.\n                    logger.warn(\"Received EOF packet from server, apparent\"\n                                + \" master disconnected. It's may be duplicate slaveId , check instance config\");\n                    return false;\n                } else {\n                    // Should not happen.\n                    throw new IOException(\"Unexpected response \" + mark + \" while fetching binlog: packet #\" + netnum\n                                          + \", len = \" + netlen);\n                }\n            }\n","sourceCodeStart":89,"sourceCodeEnd":125,"githubUrl":"https://github.com/alibaba/canal/blob/87be50e87686a3e8af08c368d0e1ffd1f59eb04a/parse/src/main/java/com/alibaba/otter/canal/parse/inbound/mysql/dbsync/DirectLogFetcher.java#L89-L125","documentation":"Thrown as ServerLogPurgedException when the MySQL master returns error packet mark 255 during binlog streaming (DirectLogFetcher.fetch()) and the error message contains 'not find first log file name' or 'purged binary logs'. This is MySQL error 1236 — the binlog file or position Canal requested for the DUMP command no longer exists on the server because it was purged. The exception is a distinct type (ServerLogPurgedException, extends CanalException) so callers can handle it specifically.","triggerScenarios":"After Canal sends COM_BINLOG_DUMP or COM_BINLOG_DUMP_GTID with a start position, the master replies with an error packet whose errmsg field matches the purge patterns. This happens when the requested binlog file was deleted by expire_logs_days / binlog_expire_logs_seconds, or when the GTID set references purged transactions.","commonSituations":"Canal was stopped for longer than expire_logs_days, so by the time it reconnects the old position is gone. A short binlog retention window (e.g. expire_logs_days=1) combined with a maintenance window. The instance.properties specifies a hardcoded binlog filename/position that is now stale. On RDS, automated binlog purging removed files faster than expected.","solutions":["Let Canal auto-discover a fresh start position by removing any stale canal.instance.master.position / binlog filename in instance.properties.","If using GTID, verify the GTID set is still available on the server: 'SHOW MASTER STATUS;' and 'SHOW BINARY LOGS;'.","Increase binlog retention: SET GLOBAL binlog_expire_logs_seconds = 604800; (7 days) on the MySQL server.","If the data gap is acceptable, restart Canal from the current master position (this skips purged transactions)."],"exampleFix":"# before — hardcoded stale position\ncanal.instance.master.position=mysql-bin.000003:4521\n\n# after — let Canal find the current position\ncanal.instance.master.position=","handlingStrategy":"retry","validationCode":"// Check that the requested binlog file still exists on the server\nResultSetPacket rs = mysqlConnection.query(\"SHOW BINARY LOGS\");\nList<String> logs = rs.getFieldValues();\n// Verify your configured start file is in the list\nboolean exists = false;\nfor (int i = 0; i < logs.size(); i += 2) {\n    if (logs.get(i).equals(configuredBinlogFile)) {\n        exists = true;\n        break;\n    }\n}\nif (!exists) {\n    // Fall back to current master position\n    logger.warn(\"Configured binlog file purged, will use current master position\");\n}","typeGuard":null,"tryCatchPattern":"try {\n    directLogFetcher.fetch();\n} catch (ServerLogPurgedException e) {\n    // Binlog position was purged — re-discover from current master status\n    logger.warn(\"Server log purged, re-discovering start position\", e);\n    EntryPosition newPos = findStartPosition(mysqlConnection);\n    // Restart dump from newPos\n}","preventionTips":["Set binlog_expire_logs_seconds high enough to cover your longest expected Canal downtime (e.g. 7 days).","Prefer GTID-based positioning which is more resilient to binlog file purging.","Monitor Canal lag and alert when it approaches the binlog retention window."],"tags":["mysql","binlog","purged","replication","gtid"],"backgroundTag":null,"analyzedSha":"87be50e87686a3e8af08c368d0e1ffd1f59eb04a","analyzedAt":"2026-08-14T04:30:11.918Z","schemaVersion":2},"datasetVersion":"2026-08-14T05:17:29.042Z"}