apache/druid · error · UnsupportedOperationException

Only DimensionSelectors which support idLookup() are support

Error message

Only DimensionSelectors which support idLookup() are supported yet

What it means

When resuming a topN scan after skipTo(previousStop), BaseTopNAlgorithm needs to translate the previous stop value into a dictionary id via the selector's idLookup(). If the DimensionSelector does not support idLookup (null), Druid throws UnsupportedOperationException because position-based resume is impossible.

Source

Thrown at processing/src/main/java/org/apache/druid/query/topn/BaseTopNAlgorithm.java:307

    public void ignoreFirstN(int n)
    {
      ignoreFirstN = n;
    }

    @Override
    public void keepOnlyN(int n)
    {
      keepOnlyN = n;
    }

    @VisibleForTesting
    public Pair<Integer, Integer> computeStartEnd(int cardinality)
    {
      int startIndex = ignoreFirstN;

      if (previousStop != null) {
        if (idLookup == null) {
          throw new UnsupportedOperationException("Only DimensionSelectors which support idLookup() are supported yet");
        }
        int lookupId = idLookup.lookupId(previousStop) + 1;
        if (lookupId < 0) {
          lookupId *= -1;
        }
        if (lookupId > ignoreFirstN + keepOnlyN) {
          startIndex = ignoreFirstN + keepOnlyN;
        } else {
          startIndex = Math.max(lookupId, startIndex);
        }
      }

      int endIndex = Math.min(ignoreFirstN + keepOnlyN, cardinality);

      final TopNOptimizationInspector topNOptimizationInspector = cursorInspector.getOptimizationInspector();
      if (ignoreAfterThreshold &&
          query.getDimensionsFilter() == null &&
          topNOptimizationInspector != null &&

View on GitHub (pinned to 9b90983fd2)

Solutions

  1. Use a plain string dimension with dictionary encoding for topN queries
  2. Remove the previousStop/time-order pagination options (run the query in one pass)
  3. Pre-materialize lookup/extraction results as a real dimension at ingestion
  4. Fall back to groupBy+limit which doesn't rely on idLookup

Example fix

// before
{ "dimension": { "type": "extraction", "dimension": "x", "extractionFn": {"type":"registeredLookup"} } }
// after
{ "dimension": "x_materialized" }  // lookup applied at ingestion
Defensive patterns

Strategy: fallback

Validate before calling

boolean safe = selector.supportsLookupNameFn() && previousStop == null || selector.idLookup() != null;

Type guard

static boolean supportsIdLookup(DimensionSelector s) { return s != null && s.idLookup() != null; }

Try / catch

try { return pagedTopNRun(query); }
catch (UnsupportedOperationException e) {
  if (e.getMessage().contains("idLookup")) { return singlePassTopNRun(query); }
  throw e;
}

Prevention

When it happens

Trigger: TopN scan with ignoreFirstN/keepOnlyN pagination hitting skipTo(previousStop) against a selector without idLookup support — e.g. expression/extraction dimensions or non-dictionary selectors combined with a non-null previousStop.

Common situations: TopN queries with time-order/pagination options on expression dimensions, cursor reuse across custom selectors lacking idLookup, dimensionSpecs (lookup/extraction) whose selectors don't implement lookup by id.

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/91a5b64b8ce0424d. Report an issue: GitHub.