apache/druid · error · UnsupportedOperationException

Not implemented

Error message

Not implemented

What it means

Bitmap64ExactCountBuildBufferAggregator.getLong(ByteBuffer, int) is an intentionally unimplemented stub. The off-heap (buffer) variant of the build aggregator stores a serialized Roaring64Bitmap in the aggregation buffer and cannot yield a long scalar, so getLong() always throws UnsupportedOperationException("Not implemented").

Source

Thrown at extensions-contrib/druid-exact-count-bitmap/src/main/java/org/apache/druid/query/aggregation/exact/count/bitmap64/Bitmap64ExactCountBuildBufferAggregator.java:71

      if (!selector.isNull()) {
        bitmap64Counter.add(selector.getLong());
      }
    }
    finally {
      buf.position(oldPosition);
    }
  }

  @Override
  public Object get(ByteBuffer buf, int position)
  {
    return getOrCreateCollector(buf, position);
  }

  @Override
  public long getLong(ByteBuffer buf, int position)
  {
    throw new UnsupportedOperationException("Not implemented");
  }

  @Override
  public double getDouble(ByteBuffer buf, int position)
  {
    throw new UnsupportedOperationException("Not implemented");
  }

  @Override
  public float getFloat(ByteBuffer buf, int position)
  {
    throw new UnsupportedOperationException("Not implemented");
  }

  @Override
  public void close()
  {

View on GitHub (pinned to 9b90983fd2)

Solutions

  1. Use the merge/counter aggregation type (whose getLong returns cardinality) in the query instead of the build type.
  2. Read the value via get(buf, position) (returns the bitmap/collector object) and call getLongCardinality() on it.
  3. Fix the query layer/post-aggregator to treat the build aggregation output as an object, not a long.
  4. If this is your fork, implement getLong() delegating to the collector's counter value if appropriate.

Example fix

// before
long v = bufferAggregator.getLong(buf, position);

// after
Object collector = bufferAggregator.get(buf, position);
long v = (collector instanceof Roaring64Bitmap)
    ? ((Roaring64Bitmap) collector).getLongCardinality()
    : 0L;
Defensive patterns

Strategy: type-guard

Validate before calling

Object c = bufferAggregator.get(buf, position); boolean ok = c instanceof Roaring64Bitmap; // then read cardinality from c

Type guard

boolean isBitmapSlot(BufferAggregator agg, ByteBuffer buf, int pos) { return agg.get(buf, pos) instanceof Roaring64Bitmap; }

Try / catch

try { v = bufferAggregator.getLong(buf, position); } catch (UnsupportedOperationException e) { v = ((Roaring64Bitmap) bufferAggregator.get(buf, position)).getLongCardinality(); }

Prevention

When it happens

Trigger: Group-by or timeseries engine finalizes a result and calls bufferAggregator.getLong(buf, position) on the bitmap build aggregation slot, e.g. because the aggregation was declared with a LONG output type or generic finalization code reads a long.

Common situations: Using the BITMAP64_BUILD_* aggregator where the merge/exact-count type was intended; custom query engines or tests calling getLong directly on buffer aggregators; post-aggregators declared over the build aggregation expecting numeric input.

Related errors


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