apache/druid · error · UnsupportedOperationException

Not implemented

Error message

Not implemented

What it means

Bitmap64ExactCountMergeBufferAggregator.getLong(ByteBuffer, int) is an intentionally unimplemented stub. The merge buffer aggregator maintains an underlying counter object per slot (counterCache) whose cardinality is exposed through its own accessor; getLong() on the buffer aggregator itself is not supported and 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/Bitmap64ExactCountMergeBufferAggregator.java:67

  {
    Object x = selector.getObject();
    if (x == null) {
      return;
    }
    Bitmap64 bitmap64Counter = counterCache.get(buf).get(position);
    bitmap64Counter.fold((RoaringBitmap64Counter) x);
  }

  @Override
  public Object get(ByteBuffer buf, int position)
  {
    return counterCache.get(buf).get(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()
  {
    counterCache.clear();

View on GitHub (pinned to 9b90983fd2)

Solutions

  1. Read the counter via get(buf, position) (counterCache.get(buf).get(position)) and take its cardinality accessor.
  2. Consume results through the standard finalization path, which uses the counter object's own accessor rather than BufferAggregator.getLong.
  3. Adjust post-aggregator/input-type declarations so the merge aggregation isn't read via getLong.
  4. Implement getLong() in the extension delegating to the counter value if direct access is required.

Example fix

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

// after
Object counter = bufferAggregator.get(buf, position);
long v = (counter instanceof Number) ? ((Number) counter).longValue() : 0L;
Defensive patterns

Strategy: type-guard

Validate before calling

Object c = bufferAggregator.get(buf, position); boolean ok = c instanceof Number || c instanceof Roaring64Bitmap; // read accordingly

Type guard

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

Try / catch

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

Prevention

When it happens

Trigger: Finalization calls bufferAggregator.getLong(buf, position) on the bitmap64 merge aggregation slot — e.g. generic group-by/timeseries result readers or post-aggregators typed LONG reading the slot directly.

Common situations: Custom query engines reading aggregation slots with getLong by default; tests enumerating BufferAggregator accessors; code ported from other aggregators (long sum) that assumes getLong works for all buffer aggregators.

Related errors


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