apache/druid · error · UnsupportedOperationException

Subqueries must be of type 'group by'

Error message

Subqueries must be of type 'group by'

What it means

mergeGroupByResultsWithoutPushDown expects the DataSource of the subquery being merged to be a QueryDataSource wrapping a GroupByQuery. When the cast fails (the wrapped query is not a GroupByQuery), an UnsupportedOperationException 'Subqueries must be of type \"group by\"' is thrown.

Solutions

  1. Rewrite the inner query as a groupBy query (groupBy can express most timeseries/topN shapes)
  2. Flatten the query into a single-level query or compute the inner query separately and use its results (e.g. via a join or inline datasource)
  3. Upgrade Druid — newer versions support more subquery types via QueryDataSource handling in the group-by engine

Example fix

// before
DataSource sub = new QueryDataSource(Druids.newTimeseriesQueryBuilder()...build());
// after
DataSource sub = new QueryDataSource(Druids.newTimeseriesQueryBuilder()...build().toGroupByQuery()); // or use a groupBy builder directly
Defensive patterns

Strategy: type-guard

Validate before calling

if (dataSource instanceof QueryDataSource && !(((QueryDataSource) dataSource).getQuery() instanceof GroupByQuery)) { throw new UnsupportedOperationException("Inner query must be a groupBy"); }

Type guard

boolean isGroupBySubquery(DataSource ds) { return ds instanceof QueryDataSource && ((QueryDataSource) ds).getQuery() instanceof GroupByQuery; }

Try / catch

try { mergeGroupByResultsWithoutPushDown(...); } catch (UnsupportedOperationException e) { /* run inner query separately or rewrite plan */ }

Prevention

When it happens

Trigger: Running a group-by with a subquery whose dataSource wraps a non-group-by query (e.g. a timeseries, topN, or scan query) such that ((QueryDataSource)dataSource).getQuery() cannot be cast to GroupByQuery.

Common situations: Nested native queries mixing engines/query types (timeseries inside groupBy); SQL-generated plans where the planner produced an unsupported nesting shape on older Druid versions; hand-built multi-level native queries.

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

Appendix: source

Thrown at processing/src/main/java/org/apache/druid/query/groupby/GroupByQueryQueryToolChest.java:280

        // Unlike withOverriddenContext's normal behavior, we want keys present in the subquery to win.
        final Map<String, Object> subqueryContext = new TreeMap<>();
        if (query.getContext() != null) {
          for (Map.Entry<String, Object> entry : query.getContext().entrySet()) {
            if (entry.getValue() != null) {
              subqueryContext.put(entry.getKey(), entry.getValue());
            }
          }
        }
        if (((QueryDataSource) dataSource).getQuery().getContext() != null) {
          subqueryContext.putAll(((QueryDataSource) dataSource).getQuery().getContext());
        }
        subqueryContext.put(GroupByQuery.CTX_KEY_SORT_BY_DIMS_FIRST, false);
        subquery = (GroupByQuery) ((QueryDataSource) dataSource).getQuery().withOverriddenContext(subqueryContext);

        closer.register(() -> groupByStatsProvider.closeQuery(subquery.context().getQueryResourceId()));
      }
      catch (ClassCastException e) {
        throw new UnsupportedOperationException("Subqueries must be of type 'group by'");
      }

      final Sequence<ResultRow> subqueryResult = mergeGroupByResults(
          subquery,
          resource,
          runner,
          context,
          closer,
          perQueryStats
      );

      final Sequence<ResultRow> finalizingResults = finalizeSubqueryResults(subqueryResult, subquery);

      if (query.getSubtotalsSpec() != null) {
        return groupingEngine.processSubtotalsSpec(
            query,
            resource,
            groupingEngine.processSubqueryResult(

View on GitHub (pinned to 9b90983fd2)