alibaba/canal · error · IOException

Unexpected response {} while fetching binlog: packet #{}, le

Error message

Unexpected response {} while fetching binlog: packet #{}, len = {}

What it means

Thrown as IOException('Unexpected response') when the first byte (mark) of a binlog dump response packet is not 0 (OK), 255 (error), or 254 (EOF). Canal considers this a protocol violation — the MySQL replication protocol defines only those three markers for the initial byte of a dump response. The exception includes the unexpected mark value, the packet sequence number, and the length.

Source

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

                    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);
                }
            }

            // if mysql is in semi mode
            if (issemi) {
                // parse semi mark
                int semimark = getUint8(NET_HEADER_SIZE + 1);
                int semival = getUint8(NET_HEADER_SIZE + 2);
                this.semival = semival;
            }

            // The first packet is a multi-packet, concatenate the packets.
            while (netlen == MAX_PACKET_LENGTH) {
                if (!fetch0(0, NET_HEADER_SIZE)) {
                    logger.warn("Reached end of input stream while fetching header");
                    return false;
                }

View on GitHub (pinned to 87be50e876)

Solutions

  1. Ensure Canal connects directly to the MySQL server (no TCP proxy in between that doesn't understand the replication protocol).
  2. Check for network corruption: verify MTU settings, switch/NIC errors on the host.
  3. If using SSL, verify the SSL configuration is correct on both sides (canal SSL settings + MySQL SSL settings).
  4. Check the MySQL server version — Canal should be compatible with the server's binlog protocol version.

Example fix

# before — routing through a generic TCP proxy
canal.instance.master.address=proxysql.internal:3306

# after — connect directly to the MySQL primary
canal.instance.master.address=mysql-primary.internal:3306
Defensive patterns

Strategy: try-catch

Try / catch

try {
    directLogFetcher.fetch();
} catch (IOException e) {
    if (e.getMessage().startsWith("Unexpected response")) {
        // Protocol violation — likely a proxy or network corruption
        logger.error("Protocol violation in binlog stream, check for proxies/corruption", e);
        // Re-establish the connection from scratch
        reconnectToMySQL();
    } else {
        throw e;
    }
}

Prevention

When it happens

Trigger: DirectLogFetcher.fetch() reads a packet whose first byte after the net header is an unrecognized value. This should never happen with a standards-compliant MySQL server. It indicates data corruption, a man-in-the-middle proxy mangling the protocol, or an incompatible/undocumented server behavior.

Common situations: A TCP proxy or connection pooler (e.g. ProxySQL, HAProxy in TCP mode) is interfering with the raw replication protocol. A network glitch corrupted the byte stream. The server is not actually MySQL (e.g. a compatible database with divergent protocol). SSL/TLS handshake left residual bytes in the buffer.

Related errors


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