apache/druid · error · UnsupportedOperationException

Reverse lookup not allowed.

Error message

Reverse lookup not allowed.

What it means

FixedIndexed only supports reverse lookup (indexOf) when the underlying values are sorted. Calling indexOf on an instance created with isSorted=false has no meaningful binary-search result, so it throws UnsupportedOperationException immediately before any search is attempted.

Solutions

  1. Only call indexOf on FixedIndexed instances known to be sorted (check the isSorted flag or the writer that produced the column)
  2. For unsorted indexes, do a linear scan comparing values instead of indexOf
  3. Ensure the writer produced sorted, unique values so the resulting FixedIndexed is sorted
  4. Upgrade Druid if your column format should produce sorted indexes (newer writers sort values)

Example fix

// before
int idx = fixedIndexed.indexOf(value);
// after
if (fixedIndexed instanceof FixedIndexed && !isSorted(fixedIndexed)) {
  int idx = -1;
  for (int i = 0; i < fixedIndexed.size(); i++) {
    if (Objects.equals(fixedIndexed.get(i), value)) { idx = i; break; }
  }
} else {
  int idx = fixedIndexed.indexOf(value);
}
Defensive patterns

Strategy: validation

Validate before calling

int safeIndexOf(FixedIndexed<?> idx, Object value) {
  return idx instanceof FrontCodedIndexed || isSortedIndex(idx)
      ? idx.indexOf(value)
      : linearScan(idx, value);
}

Type guard

boolean supportsReverseLookup(FixedIndexed<?> idx) {
  // only sorted FixedIndexed instances support indexOf
  return isSortedIndex(idx);
}

Try / catch

try {
  int i = fixedIndexed.indexOf(value);
} catch (UnsupportedOperationException e) {
  // fall back to a linear scan over the unsorted index
}

Prevention

When it happens

Trigger: Calling indexOf(value) on a FixedIndexed whose reader (e.g. FrontCodedIndexed or another FixedIndexed built from an unsorted dictionary) was opened with isSorted=false; unsorted FixedIndexed instances come from writers that wrote values in non-sorted order.

Common situations: Generic code that assumes every Indexed supports indexOf (e.g. dimension dictionary lookups, filters, or group-by code paths) hitting an unsorted index produced by a newer column format or a writer that skipped sorting; custom code reading segment columns directly.

Understand the failure class

Background: UnsupportedOperationException and "is not supported" errors: when a library deliberately refuses a call — this error's family across 30 libraries.

Related errors


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

Appendix: source

Thrown at processing/src/main/java/org/apache/druid/segment/data/FixedIndexed.java:138

  @Override
  public T get(int index)
  {
    Indexed.checkIndex(index, size);
    if (hasNull) {
      if (index == 0) {
        return null;
      }
      return typeStrategy.read(buffer, valuesOffset + ((index - 1) * width));
    } else {
      return typeStrategy.read(buffer, valuesOffset + (index * width));
    }
  }

  @Override
  public int indexOf(@Nullable T value)
  {
    if (!isSorted) {
      throw new UnsupportedOperationException("Reverse lookup not allowed.");
    }
    int minIndex = 0;
    int maxIndex = size - 1;
    while (minIndex <= maxIndex) {
      int currIndex = (minIndex + maxIndex) >>> 1;

      T currValue = get(currIndex);
      int comparison = comparator.compare(currValue, value);
      if (comparison == 0) {
        return currIndex;
      }

      if (comparison < 0) {
        minIndex = currIndex + 1;
      } else {
        maxIndex = currIndex - 1;
      }
    }

View on GitHub (pinned to 9b90983fd2)