alibaba/canal · error · IOException

ROW_RESULT is unsupported

Error message

ROW_RESULT is unsupported

What it means

Thrown while decoding a UserVarLogEvent whose value type is ROW_RESULT. The inline comment states 'this seems to be banned in MySQL altogether' — MySQL does not produce ROW_RESULT user variables in the binlog, so a well-formed MySQL stream never reaches this branch. Hitting it implies a non-MySQL source or a corrupted type byte.

Source

Thrown at dbsync/src/main/java/com/taobao/tddl/dbsync/binlog/event/UserVarLogEvent.java:109

                    value = Double.valueOf(buffer.getDouble64()); // float8get
                    break;
                case INT_RESULT:
                    if (valueLen == 8) value = Long.valueOf(buffer.getLong64()); // !uint8korr
                    else if (valueLen == 4) value = Long.valueOf(buffer.getUint32());
                    else throw new IOException("Error INT_RESULT length: " + valueLen);
                    break;
                case DECIMAL_RESULT:
                    final int precision = buffer.getInt8();
                    final int scale = buffer.getInt8();
                    value = buffer.getDecimal(precision, scale); // bin2decimal
                    break;
                case STRING_RESULT:
                    Charset charset = CharsetConversion.getNioCharset(charsetNumber);
                    value = buffer.getFixString(valueLen, charset);
                    break;
                case ROW_RESULT:
                    // this seems to be banned in MySQL altogether
                    throw new IOException("ROW_RESULT is unsupported");
                default:
                    value = null;
                    break;
            }
            buffer.limit(limit);
        }
    }

    public final String getQuery() {
        if (value == null) {
            return "SET @" + name + " := NULL";
        } else if (type == STRING_RESULT) {
            // TODO: do escaping !?
            return "SET @" + name + " := \'" + value + '\'';
        } else {
            return "SET @" + name + " := " + String.valueOf(value);
        }
    }

View on GitHub (pinned to 87be50e876)

Solutions

  1. Verify the binlog source is genuine MySQL and the event is not forged.
  2. Inspect the event with mysqlbinlog --hexdump; if corrupt, reseed from a valid position.
  3. If the source legitimately emits ROW_RESULT, patch UserVarLogEvent to skip/null the value instead of throwing.

Example fix

// before
case ROW_RESULT:
    throw new IOException("ROW_RESULT is unsupported");
// after: skip gracefully
case ROW_RESULT:
    logger.warn("ROW_RESULT user variable encountered, setting value to null");
    value = null;
    break;
Defensive patterns

Strategy: try-catch

Try / catch

try {
    userVarEvent.parse();
} catch (IOException e) {
    if (e.getMessage().equals("ROW_RESULT is unsupported")) {
        logger.warn("ROW_RESULT user variable encountered; not produced by MySQL. Skipping.");
    } else throw e;
}

Prevention

When it happens

Trigger: A UserVarLogEvent carries a type byte equal to ROW_RESULT. Not produced by standard MySQL; only seen from a forged or corrupt binlog or a non-MySQL-compatible source emulating the protocol.

Common situations: Binlog corruption flipping the type byte; a third-party tool injecting synthetic binlog events; replicating from a system that is not real MySQL.

Related errors


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