apache/cassandra · error · MarshalException

Expected 2 bytes for a smallint (%d)

Error message

Expected 2 bytes for a smallint (%d)

What it means

ShortSerializer.validate enforces that a smallint value occupies exactly 2 bytes. A buffer of any other length cannot be decoded as a 16-bit signed integer, so validation fails with a message including the actual byte count. This runs when binding values or validating data before it is stored.

Source

Thrown at src/java/org/apache/cassandra/serializers/ShortSerializer.java:43

public class ShortSerializer extends TypeSerializer<Short>
{
    public static final ShortSerializer instance = new ShortSerializer();

    public <V> Short deserialize(V value, ValueAccessor<V> accessor)
    {
        return accessor.isEmpty(value) ? null : accessor.toShort(value);
    }

    public ByteBuffer serialize(Short value)
    {
        return value == null ? ByteBufferUtil.EMPTY_BYTE_BUFFER : ByteBufferUtil.bytes(value.shortValue());
    }

    public <V> void validate(V value, ValueAccessor<V> accessor) throws MarshalException
    {
        if (accessor.size(value) != 2)
            throw new MarshalException(String.format("Expected 2 bytes for a smallint (%d)", accessor.size(value)));
    }

    public String toString(Short value)
    {
        return value == null ? "" : String.valueOf(value);
    }

    public Class<Short> getType()
    {
        return Short.class;
    }
}

View on GitHub (pinned to 88fd0f6a0e)

Solutions

  1. Bind a Java Short/short instead of a raw ByteBuffer so the driver serializes it correctly.
  2. If supplying bytes, encode exactly 2 bytes via ShortSerializer.serialize or ByteBufferUtil.bytes(shortValue).
  3. Check the column type in the schema matches the intended numeric type (CAST if needed).
  4. In tests, validate the buffer length is 2 before calling the serializer.

Example fix

// before
stmt.setBytesUnsafe(Bytes.allocate(4).putInt(v).flip()); // int-sized
// after
stmt.setShort("col", (short) v);
Defensive patterns

Strategy: validation

Validate before calling

// Java
if (value == null || value.remaining() != 2) {
    throw new IllegalArgumentException("smallint needs exactly 2 bytes, got " + (value == null ? 0 : value.remaining()));
}

Type guard

boolean isSmallintBuffer(ByteBuffer b) { return b != null && b.remaining() == 2; }

Try / catch

try {
    short s = ShortSerializer.instance.deserialize(buf.duplicate());
} catch (MarshalException e) {
    log.warn("Bad smallint: {}", e.getMessage());
}

Prevention

When it happens

Trigger: Binding a ByteBuffer whose remaining() is 0, 1, 4 (int), or 8 (long/bigint) bytes to a smallint column; passing a value serialized as another numeric type; supplying raw bytes in a test.

Common situations: Type confusion between tinyint/smallint/int/bigint columns; drivers sending raw buffers instead of typed values; application code allocating the wrong-sized buffer.

Understand the failure class

Background: Type mismatch errors: IllegalArgumentException, TypeError and type guards across 150 open-source libraries — this error's family across 150 libraries.

Related errors


AI-assisted analysis of apache/cassandra@88fd0f6a0e (2026-09-10). Data as JSON: /api/errors/44c71e67a9a2baa5. Report an issue: GitHub.