alibaba/canal · error · CanalParseException

parse failed

Error message

parse failed

What it means

Thrown as CanalParseException inside MysqlConnection.dump (the GTID-less filename+position variant) when decoder.decode(fetcher, context) returns null for an event that was fetched. A null event means the decoder could not produce a LogEvent from the bytes read, which Canal treats as an unrecoverable parse failure for that stream.

Source

Thrown at parse/src/main/java/com/alibaba/otter/canal/parse/inbound/mysql/MysqlConnection.java:173

        if (StringUtils.isNotEmpty(gtid)) {
            GTIDSet gtidSet = parseGtidSet(gtid, isMariaDB());
            if (isMariaDB()) {
                decoder.handle(LogEvent.GTID_EVENT);
                decoder.handle(LogEvent.GTID_LIST_EVENT);
            } else {
                decoder.handle(LogEvent.GTID_LOG_EVENT);
            }
            context.setGtidSet(gtidSet);
        }
        context.setCompatiablePercona(compatiablePercona);
        context.setFormatDescription(new FormatDescriptionLogEvent(4, binlogChecksum));
        while (fetcher.fetch()) {
            accumulateReceivedBytes(fetcher.limit());
            LogEvent event = null;
            event = decoder.decode(fetcher, context);

            if (event == null) {
                throw new CanalParseException("parse failed");
            }

            if (!func.sink(event)) {
                break;
            }
        }
    }

    public void dump(String binlogfilename, Long binlogPosition, SinkFunction func) throws IOException {
        updateSettings();
        loadBinlogChecksum();
        loadVersionComment();
        sendRegisterSlave();
        sendBinlogDump(binlogfilename, binlogPosition);
        DirectLogFetcher fetcher = new DirectLogFetcher(connector.getReceiveBufferSize());
        fetcher.start(connector.getChannel());
        LogDecoder decoder = new LogDecoder(LogEvent.UNKNOWN_EVENT, LogEvent.ENUM_END_EVENT);
        LogContext context = new LogContext();

View on GitHub (pinned to 87be50e876)

Solutions

  1. Check binlog_format is ROW and binlog_checksum matches what Canal negotiates (loadBinlogChecksum runs first).
  2. Upgrade Canal/driver to a release that supports the MySQL version emitting the event.
  3. If the binlog is corrupt/truncated, skip to the next valid position or restore from a clean binlog.
  4. Inspect the bytes around the failure (event type/length) to identify an unsupported event code.
Defensive patterns

Strategy: retry

Validate before calling

-- confirm checksum/format compatibility before dump
SHOW VARIABLES LIKE 'binlog_checksum';  -- ensure client negotiates it
SHOW VARIABLES LIKE 'binlog_format';   -- expect ROW

Try / catch

// decode-null is often transient corruption; bounded retry to next event
try { connection.dump(fn, pos, func); }
catch (CanalParseException e) {
    if ("parse failed".equals(e.getMessage())) { pos = advancePastCurrentEvent(pos); retryWithinLimit(); }
    else throw e;
}

Prevention

When it happens

Trigger: While fetcher.fetch() returns true in the dump loop, decoder.decode returns null. Happens with a corrupted/truncated binlog event, an unsupported event type, a binlog format/version mismatch, or a checksum incompatibility between client and server.

Common situations: MySQL version/binlog format newer than the Canal driver supports, binlog_checksum enabled on the server but not negotiated, a partial event due to network truncation, or a corrupted relay/binlog. Also after a connector bug in event decoding.

Related errors


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