alibaba/canal · error · IOException
status_vars_len ( ) > data_len ( )
Error message
status_vars_len ( ) > data_len ( )
What it means
Thrown during QueryLogEvent construction when the status variables length (statusVarsLen, read from the post-header in MySQL 5.0+ format) exceeds the minimum of the data length and MAX_SIZE_LOG_EVENT_STATUS. This catches corrupt status_vars_len values that would cause the parser to read far beyond the event boundary and potentially crash.
Source
Thrown at dbsync/src/main/java/com/taobao/tddl/dbsync/binlog/event/QueryLogEvent.java:440
final int dbLen = buffer.getUint8(); // Q_DB_LEN_OFFSET
errorCode = buffer.getUint16(); // Q_ERR_CODE_OFFSET
/*
* 5.0 format starts here. Depending on the format, we may or not have
* affected/warnings etc The remaining post-header to be parsed has
* length:
*/
int statusVarsLen = 0;
if (postHeaderLen > QUERY_HEADER_MINIMAL_LEN) {
statusVarsLen = buffer.getUint16(); // Q_STATUS_VARS_LEN_OFFSET
/*
* Check if status variable length is corrupt and will lead to very
* wrong data. We could be even more strict and require data_len to
* be even bigger, but this will suffice to catch most corruption
* errors that can lead to a crash.
*/
if (statusVarsLen > Math.min(dataLen, MAX_SIZE_LOG_EVENT_STATUS)) {
throw new IOException("status_vars_len (" + statusVarsLen + ") > data_len (" + dataLen + ")");
}
dataLen -= statusVarsLen;
}
/*
* We have parsed everything we know in the post header for QUERY_EVENT,
* the rest of post header is either comes from older version MySQL or
* dedicated to derived events (e.g. Execute_load_query...)
*/
/* variable-part: the status vars; only in MySQL 5.0 */
final int start = commonHeaderLen + postHeaderLen;
final int limit = buffer.limit(); /* for restore */
final int end = start + statusVarsLen;
buffer.position(start).limit(end);
unpackVariables(buffer, end);
buffer.position(end);
buffer.limit(limit);
/* A 2nd variable part; this is common to all versions */View on GitHub (pinned to 87be50e876)
Solutions
- Log statusVarsLen, dataLen, and MAX_SIZE_LOG_EVENT_STATUS to identify the violated constraint.
- Verify the FormatDescriptionLogEvent's postHeaderLen for QUERY_EVENT is correct for the MySQL version.
- Check if a newer MySQL version writes larger status variable blocks that exceed MAX_SIZE_LOG_EVENT_STATUS — upgrade the parser if so.
- Hex-dump the post-header region to verify the statusVarsLen byte position.
Defensive patterns
Strategy: validation
Validate before calling
// Pre-validate: check if the format version includes status vars
int postHeaderLen = descriptionEvent.postHeaderLen[header.type - 1];
if (postHeaderLen > QueryLogEvent.QUERY_HEADER_MINIMAL_LEN) {
// status vars are present — verify data length is sufficient
int dataLen = buffer.limit() - (descriptionEvent.commonHeaderLen + postHeaderLen);
if (dataLen < 0) {
logger.warn("Negative data length for QueryLogEvent with status vars");
return;
}
} Try / catch
try {
QueryLogEvent event = new QueryLogEvent(header, buffer, descriptionEvent, compatiablePercona, compress);
} catch (IOException e) {
if (e.getMessage().contains("status_vars_len")) {
logger.warn("Corrupt status_vars_len in QueryLogEvent — possible MySQL version or format mismatch");
}
throw e;
} Prevention
- Verify the FormatDescriptionLogEvent postHeaderLen for QUERY_EVENT matches the MySQL server version.
- Upgrade canal/dbsync when upgrading MySQL — newer versions may write larger status variable blocks.
- Hex-dump the post-header region to verify the status_vars_len field position.
When it happens
Trigger: When postHeaderLen > QUERY_HEADER_MINIMAL_LEN (meaning MySQL 5.0+ format with the Q_STATUS_VARS_LEN_OFFSET field), the code reads statusVarsLen as a uint16. If statusVarsLen > Math.min(dataLen, MAX_SIZE_LOG_EVENT_STATUS), the value is deemed corrupt.
Common situations: Corrupt QueryLogEvent where the status_vars_len field has a garbage value, a MySQL version that writes more status variables than the parser's MAX_SIZE_LOG_EVENT_STATUS cap allows, or buffer desynchronization causing the wrong bytes to be read as statusVarsLen.
Related errors
- skipping path
- Invalid ExecuteLoadQueryLogEvent: fn_pos_start=%d, fn_pos_en
- Query event length is too short.
- Read error:
- No such method: '{}' @ {}
AI-assisted analysis of alibaba/canal@87be50e876 (2026-08-14).
Data as JSON: /api/errors/b8c6e276df299aa7.
Report an issue: GitHub.