apache/druid · error · IllegalStateException

Cannot convert [%s]

Error message

Cannot convert [%s]

What it means

ConciseBitmapFactory.makeImmutableBitmap only knows how to convert a WrappedConciseBitmap (its own mutable type). Passing any other MutableBitmap implementation throws IllegalStateException naming the offending class, guarding against mixing bitmap implementations within one factory.

Source

Thrown at processing/src/main/java/org/apache/druid/collections/bitmap/ConciseBitmapFactory.java:96

  }

  @Override
  public MutableBitmap makeEmptyMutableBitmap()
  {
    return new WrappedConciseBitmap();
  }

  @Override
  public ImmutableBitmap makeEmptyImmutableBitmap()
  {
    return WRAPPED_IMMUTABLE_CONCISE_BITMAP;
  }

  @Override
  public ImmutableBitmap makeImmutableBitmap(MutableBitmap mutableBitmap)
  {
    if (!(mutableBitmap instanceof WrappedConciseBitmap)) {
      throw new ISE("Cannot convert [%s]", mutableBitmap.getClass());
    }
    return new WrappedImmutableConciseBitmap(
        ImmutableConciseSet.newImmutableFromMutable(
            ((WrappedConciseBitmap) mutableBitmap).getBitmap()
        )
    );
  }

  @Override
  public ImmutableBitmap mapImmutableBitmap(ByteBuffer b)
  {
    return new WrappedImmutableConciseBitmap(b.asIntBuffer());
  }

  @Override
  public ImmutableBitmap union(Iterable<ImmutableBitmap> b)
      throws ClassCastException
  {

View on GitHub (pinned to 9b90983fd2)

Solutions

  1. Create the mutable bitmap from the same factory: use conciseFactory.makeMutableBitmap() and pass that to makeImmutableBitmap()
  2. Standardize on one bitmap factory across the system (druid.processing.bitmap.type config)
  3. If conversion between types is needed, copy via iteration: create a new WrappedConciseBitmap and add all bits from the source
  4. Check where the MutableBitmap originated — a factory mismatch elsewhere is the root cause

Example fix

// before
MutableBitmap mutable = roaringFactory.makeMutableBitmap();
ImmutableBitmap immutable = conciseFactory.makeImmutableBitmap(mutable); // ISE
// after
MutableBitmap mutable = conciseFactory.makeMutableBitmap();
mutable.or(mutableFromOtherFactory);
ImmutableBitmap immutable = conciseFactory.makeImmutableBitmap(mutable);
Defensive patterns

Strategy: type-guard

Validate before calling

if (!(mutableBitmap instanceof WrappedConciseBitmap)) { throw new IllegalArgumentException("need a bitmap from ConciseBitmapFactory"); }

Type guard

static boolean isConciseMutable(MutableBitmap b) { return b instanceof WrappedConciseBitmap; }

Try / catch

try { ImmutableBitmap im = factory.makeImmutableBitmap(mb); } catch (IllegalStateException e) { /* wrong factory: rebuild via makeMutableBitmap and copy bits */ }

Prevention

When it happens

Trigger: Calling makeImmutableBitmap() with a mutable bitmap created by a different factory (e.g. WrappedRoaringBitmap or RoaringBitmapFactory's mutable type) instead of one from ConciseBitmapFactory.makeMutableBitmap().

Common situations: Configuring different bitmap factories for different components (e.g. index vs query) so bitmaps cross factory boundaries; refactoring code that switched to Roaring while a utility still uses Concise; passing generic MutableBitmap parameters built elsewhere.

Understand the failure class

Background: "is not a compatible type" / "cannot merge" errors: when a value's type doesn't match what the library requires — this error's family across 65 libraries.

Related errors


AI-assisted analysis of apache/druid@9b90983fd2 (2026-09-07). Data as JSON: /api/errors/91e01fe43260f8fd. Report an issue: GitHub.