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

  1. Log statusVarsLen, dataLen, and MAX_SIZE_LOG_EVENT_STATUS to identify the violated constraint.
  2. Verify the FormatDescriptionLogEvent's postHeaderLen for QUERY_EVENT is correct for the MySQL version.
  3. Check if a newer MySQL version writes larger status variable blocks that exceed MAX_SIZE_LOG_EVENT_STATUS — upgrade the parser if so.
  4. 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

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


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