apache/shardingsphere · error · SQLFeatureNotSupportedException

Wrong length `%d` of MYSQL_TYPE_DATE

Error message

Wrong length `%d` of MYSQL_TYPE_DATE

What it means

Thrown when a MySQL binary-protocol TIME value has a length byte other than 0 (zero time), 8 (time), or 12 (time with microseconds). Note the message says MYSQL_TYPE_DATE although it is thrown by the TIME reader in MySQLTimeBinaryProtocolValue — the names are swapped relative to the DATE class. Any other length indicates malformed data or stream desynchronization.

Source

Thrown at database/protocol/dialect/mysql/src/main/java/org/apache/shardingsphere/database/protocol/mysql/packet/command/query/binary/execute/protocol/MySQLTimeBinaryProtocolValue.java:48

/**
 * Binary protocol value for time for MySQL.
 */
public final class MySQLTimeBinaryProtocolValue implements MySQLBinaryProtocolValue {
    
    @Override
    public Object read(final MySQLPacketPayload payload, final boolean unsigned) throws SQLException {
        int length = payload.readInt1();
        switch (length) {
            case 0:
                return new Timestamp(0L);
            case 8:
                return getTimestamp(payload);
            case 12:
                Timestamp result = getTimestamp(payload);
                result.setNanos(payload.readInt4() * 1000);
                return result;
            default:
                throw new SQLFeatureNotSupportedException(String.format("Wrong length `%d` of MYSQL_TYPE_DATE", length));
        }
    }
    
    private Timestamp getTimestamp(final MySQLPacketPayload payload) {
        payload.readInt1();
        payload.readInt4();
        Timestamp result = Timestamp.valueOf(LocalDateTime.of(0, 1, 1, payload.readInt1(), payload.readInt1(), payload.readInt1()));
        result.setNanos(0);
        return result;
    }
    
    @Override
    public void write(final MySQLPacketPayload payload, final Object value) {
        LocalDateTime localDateTime = LocalDateTime.ofInstant(Instant.ofEpochMilli(((Time) value).getTime()), ZoneId.systemDefault());
        int hours = localDateTime.getHour();
        int minutes = localDateTime.getMinute();
        int seconds = localDateTime.getSecond();
        int nanos = localDateTime.getNano();

View on GitHub (pinned to e952770a21)

Solutions

  1. Treat the 'DATE' text as a known mislabel; the failing value is a TIME column
  2. Verify the preceding columns' binary sizes to rule out reader desynchronization; test with text protocol (useServerPrepStmts=false)
  3. Check the server is stock MySQL at a supported version
  4. Report upstream with server version, column types, and the failing length value
Defensive patterns

Strategy: try-catch

Try / catch

try {
    value = timeBinaryProtocolValue.read(payload, unsigned);
} catch (SQLFeatureNotSupportedException ex) {
    // length not in {0,8,12}: capture the resultset bytes and compare against the MySQL binary protocol spec
    log.warn("binary time decode failed: {}", ex.getMessage());
    throw ex;
}

Prevention

When it happens

Trigger: MySQLTimeBinaryProtocolValue.read() gets a length byte not in {0,8,12} — corrupted packet, reader misalignment after a previous column, or a nonstandard server encoding.

Common situations: Binary prepared-statement resultsets containing TIME columns read after a wrongly-sized earlier field; non-MySQL clients on the MySQL port; forks with divergent binary TIME encodings.

Related errors


AI-assisted analysis of apache/shardingsphere@e952770a21 (2026-08-14). Data as JSON: /api/errors/f049ca90bf823113. Report an issue: GitHub.