{"record":{"id":"64637c83a8246137","repo":"apache/cassandra","slug":"expected-0-or-at-least-4-bytes-d","errorCode":null,"errorMessage":"Expected 0 or at least 4 bytes (%d)","messagePattern":"Expected 0 or at least 4 bytes \\((.+?)\\)","errorType":"validation","errorClass":"MarshalException","httpStatus":null,"severity":"error","filePath":"src/java/org/apache/cassandra/serializers/DecimalSerializer.java","lineNumber":62,"sourceCode":"        if (value == null)\n            return ByteBufferUtil.EMPTY_BYTE_BUFFER;\n\n        BigInteger bi = value.unscaledValue();\n        int scale = value.scale();\n        byte[] bibytes = bi.toByteArray();\n\n        ByteBuffer bytes = ByteBuffer.allocate(4 + bibytes.length);\n        bytes.putInt(scale);\n        bytes.put(bibytes);\n        bytes.rewind();\n        return bytes;\n    }\n\n    public <T> void validate(T value, ValueAccessor<T> accessor) throws MarshalException\n    {\n        // We at least store the scale.\n        if (!accessor.isEmpty(value) && accessor.size(value) < 4)\n            throw new MarshalException(String.format(\"Expected 0 or at least 4 bytes (%d)\", accessor.size(value)));\n    }\n\n    public String toString(BigDecimal value)\n    {\n        return value == null ? \"\" : value.toString();\n    }\n\n    public Class<BigDecimal> getType()\n    {\n        return BigDecimal.class;\n    }\n}\n","sourceCodeStart":44,"sourceCodeEnd":75,"githubUrl":"https://github.com/apache/cassandra/blob/88fd0f6a0eaed8943f05ac9e8f947882b8ddc8f1/src/java/org/apache/cassandra/serializers/DecimalSerializer.java#L44-L75","documentation":"DecimalSerializer serializes a BigDecimal as a 4-byte scale followed by an unscaled integer. A non-empty decimal value must therefore be at least 4 bytes; anything in between cannot even hold the scale field, so validate() rejects it with this formatted MarshalException including the actual byte size.","triggerScenarios":"validate/deserialize called on a non-empty buffer of 1-3 bytes — e.g. a decimal column cell truncated, bytes of a different type stored in a decimal column, or a manual buffer written without the 4-byte scale.","commonSituations":"Schema drift (column type changed but old bytes remain); hand-crafted test data missing the scale integer; corruption from partial writes.","solutions":["Write decimal values via DecimalSerializer.serialize(BigDecimal) so the 4-byte scale is always present","Check the column type matches the stored bytes (schema mismatch)","If data is truncated on disk, restore from backup or repair","Pad manual buffers to include the scale (4 bytes) plus unscaled value"],"exampleFix":"// before\nByteBuffer bad = ByteBufferUtil.bytes(new byte[]{1, 2}); // 2 bytes, no scale\n// after\nByteBuffer ok = DecimalSerializer.instance.serialize(new BigDecimal(\"1.23\")); // scale + unscaled","handlingStrategy":"validation","validationCode":"public static void checkDecimal(ByteBuffer buf) {\n    if (buf != null && buf.hasRemaining() && buf.remaining() < 4)\n        throw new MarshalException(\"decimal value too short: \" + buf.remaining());\n}","typeGuard":"public static boolean isValidDecimalBytes(ByteBuffer buf) {\n    return buf == null || !buf.hasRemaining() || buf.remaining() >= 4;\n}","tryCatchPattern":"try {\n    decimalType.validate(value);\n} catch (MarshalException e) {\n    logger.warn(\"Invalid decimal bytes: {}\", e.getMessage());\n}","preventionTips":["Always serialize via DecimalSerializer.serialize(BigDecimal)","Check column type matches data when reusing raw bytes","Guard against partial writes with checksums"],"tags":["serialization","cassandra","decimal","validate"],"backgroundTag":"invalid-argument-format","analyzedSha":"88fd0f6a0eaed8943f05ac9e8f947882b8ddc8f1","analyzedAt":"2026-09-10T07:29:22.284Z","contentChangedAt":"2026-09-10T07:29:22.284Z","schemaVersion":2},"datasetVersion":"2026-09-14T16:17:12.679Z"}