apache/cassandra · error · InvalidTypeException

Invalid boolean value, expecting 1 byte but got

Error message

Invalid boolean value, expecting 1 byte but got 

What it means

The boolean codec's deserializeNoBoxing() expects exactly 1 byte on the wire (any nonzero byte is true). A buffer whose remaining size differs from 1 means the bytes are not a CQL boolean, so the codec throws instead of guessing.

Source

Thrown at src/java/org/apache/cassandra/cql3/functions/types/TypeCodec.java:1279

        @Override
        public String format(Boolean value)
        {
            if (value == null) return "NULL";
            return value ? "true" : "false";
        }

        @Override
        public ByteBuffer serializeNoBoxing(boolean value, ProtocolVersion protocolVersion)
        {
            return value ? TRUE.duplicate() : FALSE.duplicate();
        }

        @Override
        public boolean deserializeNoBoxing(ByteBuffer bytes, ProtocolVersion protocolVersion)
        {
            if (bytes == null || bytes.remaining() == 0) return false;
            if (bytes.remaining() != 1)
                throw new InvalidTypeException(
                "Invalid boolean value, expecting 1 byte but got " + bytes.remaining());

            return bytes.get(bytes.position()) != 0;
        }
    }

    /**
     * This codec maps a CQL {@link DataType#decimal()} to a Java {@link BigDecimal}.
     */
    private static class DecimalCodec extends TypeCodec<BigDecimal>
    {

        private static final DecimalCodec instance = new DecimalCodec();

        private DecimalCodec()
        {
            super(DataType.decimal(), BigDecimal.class);
        }

View on GitHub (pinned to 88fd0f6a0e)

Solutions

  1. Encode booleans as exactly one byte: ByteBuffer.allocate(1).put((byte)(b ? 1 : 0)).
  2. Match the codec to the actual column type (tinyint codec for 1-byte signed ints, etc.).
  3. Refresh cached prepared statements after schema type changes.
  4. If bytes come from a custom format, slice/repack to 1 byte before handing them to the codec.

Example fix

// before
ByteBuffer b = ByteBuffer.allocate(2).putShort((short)1);
booleanCodec.deserializeNoBoxing(b, version); // throws: got 2 bytes
// after
ByteBuffer b = ByteBuffer.allocate(1).put((byte)1);
booleanCodec.deserializeNoBoxing(b, version); // true
Defensive patterns

Strategy: type-guard

Validate before calling

if (bytes == null || bytes.remaining() != 1)
    throw new IllegalArgumentException("boolean needs exactly 1 byte, got " + (bytes == null ? 0 : bytes.remaining()));

Type guard

boolean isBooleanBuffer(ByteBuffer b) {
    return b != null && b.remaining() == 1;
}

Try / catch

try {
    return booleanCodec.deserializeNoBoxing(bytes, protocolVersion);
} catch (InvalidTypeException e) {
    log.warn("Non-boolean payload ({} bytes), treating as false", bytes.remaining());
    return false;
}

Prevention

When it happens

Trigger: Calling booleanCodec.deserializeNoBoxing(bytes, protocolVersion) where bytes.remaining() != 1 — e.g. decoding an int, tinyint, or text column's bytes with the boolean codec.

Common situations: Column type changed between boolean and tinyint/int; storing "true"/"false" text in a column read as boolean; manual byte buffers that put more than one byte (e.g. putInt); custom protocol implementations writing padded values.

Related errors


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