{"record":{"id":"cb19a176e70a6fa1","repo":"elastic/elasticsearch","slug":"bitmap-terms-query-value-is-not-a-valid-serializ","errorCode":null,"errorMessage":"[bitmap_terms] query value is not a valid serialized RoaringBitmap","messagePattern":"\\[bitmap_terms\\] query value is not a valid serialized RoaringBitmap","errorType":"validation","errorClass":"IllegalArgumentException","httpStatus":400,"severity":"error","filePath":"modules/bitmap/src/main/java/org/elasticsearch/index/query/bitmapterms/BitmapTermsQueryBuilder.java","lineNumber":186,"sourceCode":"        BitmapValues values = switch (numberFieldType.numberType()) {\n            case INTEGER -> integerValues(bitmapBytes);\n            case LONG -> longValues(bitmapBytes);\n            default -> throw new AssertionError(\"unexpected number type [\" + numberFieldType.numberType() + \"]\");\n        };\n        // The two queries differ only in which index structure they merge against; the field's width\n        // is carried by the BitmapValues.\n        if (numberFieldType.isIndexedWithTerms()) {\n            return new BitmapTermsQuery(fieldName, values);\n        }\n        return new BitmapBKDQuery(fieldName, values);\n    }\n\n    private static IntBitmap integerValues(byte[] bitmapBytes) {\n        IntBitmap bitmap;\n        try {\n            bitmap = IntBitmap.deserialize(bitmapBytes);\n        } catch (Exception e) {\n            throw new IllegalArgumentException(\"[bitmap_terms] query value is not a valid serialized RoaringBitmap\", e);\n        }\n        if (bitmap.hasNegativeValues()) {\n            throw new IllegalArgumentException(\n                \"[bitmap_terms] query on [integer] field only supports non-negative values (0 to 2147483647)\"\n            );\n        }\n        return bitmap;\n    }\n\n    private static LongBitmap longValues(byte[] bitmapBytes) {\n        LongBitmap bitmap;\n        try {\n            bitmap = LongBitmap.deserializePortable(bitmapBytes);\n        } catch (Exception e) {\n            throw new IllegalArgumentException(\n                \"[bitmap_terms] query value is not a valid serialized 64-bit RoaringBitmap in the portable format\",\n                e\n            );","sourceCodeStart":168,"sourceCodeEnd":204,"githubUrl":"https://github.com/elastic/elasticsearch/blob/db6a809a667c081ca1dc7500389d26975573215f/modules/bitmap/src/main/java/org/elasticsearch/index/query/bitmapterms/BitmapTermsQueryBuilder.java#L168-L204","documentation":"Thrown by integerValues when IntBitmap.deserialize fails on the decoded bytes. The bytes were valid base64 but do not form a valid serialized 32-bit RoaringBitmap (wrong cookie/header, truncated, or a 64-bit portable-format payload supplied to an integer field).","triggerScenarios":"Supplying a Roaring64NavigableMap.serializePortable payload to an integer field; supplying a portable vs run-length-laid-out 32-bit bitmap that the deserializer rejects; truncated bytes from a wrong encoder. Note the integer path expects the format from RoaringBitmap.serialize / pyroaring BitMap.serialize.","commonSituations":"Reusing the same base64 blob across integer and long fields; client using the wrong Roaring serialization method; version skew between the Roaring library on the client and server.","solutions":["For integer fields, serialize with 32-bit RoaringBitmap.serialize (java) or pyroaching BitMap.serialize, then base64-encode.","Do not feed a 64-bit/portable-format payload to an integer field; use a long field for 64-bit bitmaps.","Verify the byte length and cookie header match the 32-bit roaring format before sending."],"exampleFix":"// before: 64-bit portable bytes sent to integer field\nbitmap = Roaring64NavigableMap(); bitmap.add(...); value = base64(bitmap.serializePortable())\n// after: 32-bit bitmap for integer field\nbitmap = RoaringBitmap(); bitmap.add(...); value = base64(bitmap.serialize())","handlingStrategy":"validation","validationCode":"// Round-trip the bitmap on the client to ensure it deserializes before sending.\nimport org.roaringbitmap.RoaringBitmap;\nbyte[] bytes = ...; // your serialized 32-bit bitmap\nRoaringBitmap r = RoaringBitmap.deserialize(ByteBuffer.wrap(bytes));\nif (r.hasNegativeValuesRunningLengthIntervals()) throw new IllegalArgumentException(\"invalid\");\nString value = Base64.getEncoder().encodeToString(bytes);","typeGuard":null,"tryCatchPattern":null,"preventionTips":["For integer fields always use the 32-bit RoaringBitmap.serialize output.","Round-trip deserialize locally before sending to catch format mismatches early."],"tags":["bitmap-terms","roaring-bitmap","serialization","elasticsearch"],"analyzedSha":"db6a809a667c081ca1dc7500389d26975573215f","analyzedAt":"2026-08-12T01:39:14.192Z","schemaVersion":2},"datasetVersion":"2026-08-12T12:17:08.281Z"}