{"record":{"id":"e7f5edea9eb24a62","repo":"apache/druid","slug":"failed-to-deserialize-to-roaringbitmap64counter-i","errorCode":null,"errorMessage":"Failed to deserialize to RoaringBitmap64Counter, input is an invalid base64 string","messagePattern":"Failed to deserialize to RoaringBitmap64Counter, input is an invalid base64 string","errorType":"validation","errorClass":"IllegalArgumentException","httpStatus":null,"severity":"error","filePath":"extensions-contrib/druid-exact-count-bitmap/src/main/java/org/apache/druid/query/aggregation/exact/count/bitmap64/Bitmap64ExactCountMergeComplexMetricSerde.java","lineNumber":57,"sourceCode":"  static RoaringBitmap64Counter deserializeRoaringBitmap64Counter(final Object object)\n  {\n    if (object instanceof String) {\n      return RoaringBitmap64Counter.fromBytes(decodeStringToByteArray((String) object));\n    } else if (object instanceof byte[]) {\n      return RoaringBitmap64Counter.fromBytes((byte[]) object);\n    } else if (object instanceof RoaringBitmap64Counter) {\n      return (RoaringBitmap64Counter) object;\n    }\n    throw new IAE(\"Cannot deserialize type[%s] to an RoaringBitmap64Counter:\", object.getClass().getName());\n  }\n\n  private static byte[] decodeStringToByteArray(String string)\n  {\n    try {\n      return StringUtils.decodeBase64(StringUtils.toUtf8(string));\n    }\n    catch (IllegalArgumentException e) {\n      throw new IAE(\"Failed to deserialize to RoaringBitmap64Counter, input is an invalid base64 string\");\n    }\n  }\n\n  @Override\n  public String getTypeName()\n  {\n    return Bitmap64ExactCountModule.TYPE_NAME; // must be common type name\n  }\n\n  @Override\n  public ObjectStrategy getObjectStrategy()\n  {\n    return Bitmap64ExactCountObjectStrategy.STRATEGY;\n  }\n\n  @Override\n  public ComplexMetricExtractor getExtractor()\n  {","sourceCodeStart":39,"sourceCodeEnd":75,"githubUrl":"https://github.com/apache/druid/blob/9b90983fd291f26935af934383ce360473179e4d/extensions-contrib/druid-exact-count-bitmap/src/main/java/org/apache/druid/query/aggregation/exact/count/bitmap64/Bitmap64ExactCountMergeComplexMetricSerde.java#L39-L75","documentation":"decodeStringToByteArray wraps StringUtils.decodeBase64 and converts any IllegalArgumentException from the decoder into IllegalArgumentException(\"Failed to deserialize to RoaringBitmap64Counter, input is an invalid base64 string\"). It is thrown when the String form of a serialized RoaringBitmap64Counter cannot be base64-decoded, meaning the string is malformed (wrong charset, truncated, whitespace/newlines, or not base64 at all).","triggerScenarios":"deserializeRoaringBitmap64Counter receives a String whose content is not valid base64 — e.g. an unencoded raw serialization, a hex string, a value with padding/newline issues, or a JSON field that got URL-encoded somewhere upstream.","commonSituations":"Producing the serialized value with a different bitmap library or encoding (hex instead of base64); manually copying bitmap strings between systems and truncating them; transport layers (HTTP query params, CSV) mangling base64 (e.g. stripping '+'); loading data exported in a non-base64 format.","solutions":["Validate the string is well-formed base64 before ingestion: Base64.getDecoder().decode(str) in a try-catch, or a regex check for ^[A-Za-z0-9+/]*={0,2}$.","Confirm the producer encodes with base64 (StringUtils.encodeBase64 / Base64 encoder), not hex or raw bytes-as-string.","Check the transport: if the string passes through URLs or CSV, ensure '+', '/', and '=' are not mangled (use URL-safe base64 or proper escaping end-to-end).","Regenerate the value from the original RoaringBitmap64Counter if the string may have been corrupted or truncated in transit."],"exampleFix":"// before\nString s = row.getString(col); // could be hex or invalid\nserde.extractValue(s);\n// after\nString s = row.getString(col);\nif (s != null && s.matches(\"[A-Za-z0-9+/]+={0,2}\")) {\n  serde.extractValue(s);\n} else {\n  byte[] raw = Hex.decodeHex(s.toCharArray()); // decode hex, then base64-encode\n  s = Base64.getEncoder().encodeToString(raw);\n  serde.extractValue(s);\n}","handlingStrategy":"validation","validationCode":"static boolean isValidBase64(String s) {\n  if (s == null || s.isEmpty()) return false;\n  try { java.util.Base64.getDecoder().decode(s); return true; }\n  catch (IllegalArgumentException e) { return false; }\n}","typeGuard":null,"tryCatchPattern":"try {\n  RoaringBitmap64Counter c = serde.extractValue(base64String);\n} catch (IllegalArgumentException e) {\n  if (e.getMessage().contains(\"invalid base64\")) {\n    // re-encode from source bytes or quarantine the record\n  } else {\n    throw e;\n  }\n}","preventionTips":["Always base64-encode serialized bitmaps at the producer (StringUtils.encodeBase64 / java.util.Base64).","Use URL-safe base64 or proper percent-encoding when the string travels through URLs, query params, or CSV.","Run a decode round-trip (encode then decode) in integration tests to catch transport corruption.","Reject malformed strings at parse time with a clear per-record error instead of failing mid-query."],"tags":["deserialization","base64","invalid-argument-format","druid"],"backgroundTag":"invalid-argument-format","analyzedSha":"9b90983fd291f26935af934383ce360473179e4d","analyzedAt":"2026-09-07T13:32:30.957Z","contentChangedAt":"2026-09-07T13:32:30.957Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}