alibaba/canal · critical · ServerLogPurgedException

errno = {}, sqlstate = {} errmsg = {}

Error message

 errno = {}, sqlstate = {} errmsg = {}

What it means

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.

Source

Thrown at parse/src/main/java/com/alibaba/otter/canal/parse/inbound/mysql/dbsync/DirectLogFetcher.java:107

                return false;
            }

            // Detecting error code.
            final int mark = getUint8(NET_HEADER_SIZE);
            if (mark != 0) {
                if (mark == 255) // error from master
                {
                    // Indicates an error, for example trying to fetch from
                    // wrong
                    // binlog position.
                    position = NET_HEADER_SIZE + 1;
                    final int errno = getInt16();
                    String sqlstate = forward(1).getFixString(SQLSTATE_LENGTH);
                    String errmsg = getFixString(limit - position);
                    if (StringUtils.containsIgnoreCase(errmsg, "not find first log file name")
                        || StringUtils.containsIgnoreCase(errmsg, "purged binary logs")) {
                        // 开始 dump 后,server 位点过期,DUMP 和 DUMP_GTID 两种错误信息
                        throw new ServerLogPurgedException(
                            " errno = " + errno + ", sqlstate = " + sqlstate + " errmsg = " + errmsg);
                    }

                    throw new IOException("Received error packet:" + " errno = " + errno + ", sqlstate = " + sqlstate
                                          + " errmsg = " + errmsg);
                } else if (mark == 254) {
                    // Indicates end of stream. It's not clear when this would
                    // be sent.
                    logger.warn("Received EOF packet from server, apparent"
                                + " master disconnected. It's may be duplicate slaveId , check instance config");
                    return false;
                } else {
                    // Should not happen.
                    throw new IOException("Unexpected response " + mark + " while fetching binlog: packet #" + netnum
                                          + ", len = " + netlen);
                }
            }

View on GitHub (pinned to 87be50e876)

Solutions

  1. Let Canal auto-discover a fresh start position by removing any stale canal.instance.master.position / binlog filename in instance.properties.
  2. If using GTID, verify the GTID set is still available on the server: 'SHOW MASTER STATUS;' and 'SHOW BINARY LOGS;'.
  3. Increase binlog retention: SET GLOBAL binlog_expire_logs_seconds = 604800; (7 days) on the MySQL server.
  4. If the data gap is acceptable, restart Canal from the current master position (this skips purged transactions).

Example fix

# before — hardcoded stale position
canal.instance.master.position=mysql-bin.000003:4521

# after — let Canal find the current position
canal.instance.master.position=
Defensive patterns

Strategy: retry

Validate before calling

// Check that the requested binlog file still exists on the server
ResultSetPacket rs = mysqlConnection.query("SHOW BINARY LOGS");
List<String> logs = rs.getFieldValues();
// Verify your configured start file is in the list
boolean exists = false;
for (int i = 0; i < logs.size(); i += 2) {
    if (logs.get(i).equals(configuredBinlogFile)) {
        exists = true;
        break;
    }
}
if (!exists) {
    // Fall back to current master position
    logger.warn("Configured binlog file purged, will use current master position");
}

Try / catch

try {
    directLogFetcher.fetch();
} catch (ServerLogPurgedException e) {
    // Binlog position was purged — re-discover from current master status
    logger.warn("Server log purged, re-discovering start position", e);
    EntryPosition newPos = findStartPosition(mysqlConnection);
    // Restart dump from newPos
}

Prevention

When it happens

Trigger: 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.

Common situations: 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.

Related errors


AI-assisted analysis of alibaba/canal@87be50e876 (2026-08-14). Data as JSON: /api/errors/77fd77bb34cc8283. Report an issue: GitHub.