apache/shardingsphere · critical · PipelineInternalException
Decode binlog event failed, errorCode: %d, sqlState: %s, err
Error message
Decode binlog event failed, errorCode: %d, sqlState: %s, errorMessage: %s
What it means
During MySQL incremental ingestion, MySQLBinlogEventPacketDecoder.checkPayload reads the status header of each replicated packet; a leading 0xFF byte marks a MySQL ERR packet, and the decoder throws PipelineInternalException carrying the server's error number, SQL state, and message. In other words: the MySQL server itself rejected the binlog dump stream and the pipeline surfaced it verbatim.
Source
Thrown at kernel/data-pipeline/dialect/mysql/src/main/java/org/apache/shardingsphere/data/pipeline/mysql/ingest/incremental/client/netty/MySQLBinlogEventPacketDecoder.java:102
skipChecksum(binlogEventHeader.getEventType(), in);
return;
}
if (decodeWithTX) {
processEventWithTX(binlogEvent.get(), out);
} else {
processEventIgnoreTX(binlogEvent.get(), out);
}
skipChecksum(binlogEventHeader.getEventType(), in);
}
}
private void checkPayload(final MySQLPacketPayload payload) {
int statusCode = payload.readInt1();
if (255 == statusCode) {
int errorNo = payload.readInt2();
payload.skipReserved(1);
String sqlState = payload.readStringFix(5);
throw new PipelineInternalException("Decode binlog event failed, errorCode: %d, sqlState: %s, errorMessage: %s", errorNo, sqlState, payload.readStringEOF());
}
if (0 != statusCode) {
log.debug("Illegal binlog status code {}, remaining packet \n{}", statusCode, readRemainPacket(payload));
}
}
private String readRemainPacket(final MySQLPacketPayload payload) {
return ByteBufUtil.hexDump(payload.readStringFixByBytes(payload.getByteBuf().readableBytes()));
}
private boolean checkEventIntegrity(final ByteBuf in, final MySQLBinlogEventHeader binlogEventHeader) {
if (in.readableBytes() < binlogEventHeader.getEventSize() - MySQLBinlogEventHeader.MYSQL_BINLOG_EVENT_HEADER_LENGTH) {
log.debug("the event body is not complete, event size={}, readable bytes={}", binlogEventHeader.getEventSize(), in.readableBytes());
in.resetReaderIndex();
return false;
}
return true;
}View on GitHub (pinned to e952770a21)
Solutions
- Read errorCode/sqlState/errorMessage from the exception — e.g. 1227/1236 map to privilege and binlog-availability problems — and fix that server-side condition.
- Grant REPLICATION SLAVE, REPLICATION CLIENT (and SELECT for the dump) to the pipeline user and restart the incremental task.
- Ensure log-bin is enabled with binlog_format=ROW and that the requested position/GTID still exists (SHOW BINARY LOGS); re-anchor the job if purged.
- If the error is transient (restart), restart the pipeline job to re-request the stream from the recorded position.
Example fix
-- before: user lacks privileges GRANT SELECT ON db.* TO 'pipeline'@'%'; -- after GRANT SELECT, REPLICATION SLAVE, REPLICATION CLIENT ON *.* TO 'pipeline'@'%';
Defensive patterns
Strategy: validation
Validate before calling
// preflight replication readiness on MySQL source
try (Statement st = sourceConnection.createStatement()) {
ResultSet rs = st.executeQuery("SHOW VARIABLES LIKE 'log_bin'"); // must be ON
ResultSet rs2 = st.executeQuery("SHOW MASTER STATUS"); // binlog exists
ResultSet rs3 = st.executeQuery("SHOW GRANTS FOR CURRENT_USER()"); // must include REPLICATION SLAVE
} Try / catch
try {
channel.connect(); // binlog stream
} catch (final PipelineInternalException ex) {
if (ex.getMessage().contains("Decode binlog event failed")) {
// parse errorCode; 1236 -> purged binlog/privileges: re-anchor position or fix grants, then restart job
}
} Prevention
- Grant REPLICATION SLAVE/CLIENT to the pipeline user before creating migration jobs.
- Set binlog_format=ROW and verify with SHOW VARIABLES before starting incremental ingest.
- Size binlog retention (expire_logs_days / binlog_expire_logs_seconds) larger than the longest expected job pause so positions are never purged.
When it happens
Trigger: Starting or running binlog replication where the server responds with an error packet: missing REPLICATION SLAVE/CLIENT privilege, binlog file/position no longer available (purged), binlog not enabled, or the account is blocked from connecting a replica stream.
Common situations: Pipeline/migration job user lacks REPLICATION privileges; specified binlog position/GTID purged by expire_logs_days; binlog_format=STATEMENT where ROW is required; MySQL restarted with different binlog settings mid-job.
Related errors
- MySQL BLOB type meta in binlog should be range 1 to 4, but a
- MySQL JSON type meta in binlog should be range 1 to 4, but a
- MySQL Enum meta in binlog only include value 1 or 2, but act
- Unknown rowEventType: %s
- Unknown rowEventType: %s
AI-assisted analysis of apache/shardingsphere@e952770a21 (2026-08-14).
Data as JSON: /api/errors/6735bc9396e87b4e.
Report an issue: GitHub.