apache/druid · error · UnsupportedOperationException
Must use 'filter' or 'always' havingSpec
Error message
Must use 'filter' or 'always' havingSpec
What it means
GroupByPostShuffleFrameProcessor.cloneHavingSpec can only clone HavingSpec types it supports (DimFilterHavingSpec and AlwaysHavingSpec), so the cloned having spec can be attached to the derived query. Any other HavingSpec implementation triggers this UnsupportedOperationException because the processor cannot rewrite it correctly for the post-shuffle query.
Solutions
- Replace the having spec with a DimFilterHavingSpec (a filter-based HAVING clause, e.g. HAVING SUM(x) > 10 in SQL).
- In SQL, express the HAVING condition as a standard filter so it compiles to DimFilterHavingSpec.
- Move the having logic into an outer query (subquery aggregation, then filter outside).
- Remove the havingSpec and filter results client-side if unsupported.
Example fix
// before (native groupBy)
"havingSpec": {"type": "greaterThan", "aggregation": "agg", "value": 10}
// after
"havingSpec": {"type": "filter", "dimFilter": {"type": "expression", "expression": "\"agg\" > 10"}} Defensive patterns
Strategy: validation
Validate before calling
// Check the havingSpec type before submitting a group-by through MSQ
if (q.havingSpec && !['filter', 'always'].includes(q.havingSpec.type)) {
throw new Error('MSQ group-by supports only filter/always havingSpec; got: ' + q.havingSpec.type);
} Type guard
const hasSupportedHaving = (q) => !q.havingSpec || q.havingSpec.type === 'filter' || q.havingSpec.type === 'always';
Prevention
- Use filter-based (DimFilterHavingSpec) having specs exclusively.
- Express HAVING conditions as standard SQL filters.
- Avoid legacy comparator having specs and custom HavingSpec implementations in MSQ queries.
When it happens
Trigger: Running a group-by query through MSQ post-shuffle processing where the query's havingSpec is neither a DimFilterHavingSpec nor an AlwaysHavingSpec (e.g. a legacy ComparatorHavingSpec, or a custom HavingSpec).
Common situations: Older/native queries using comparator-based having specs (e.g. 'greaterThan' numeric having) submitted through SQL/MSQ; custom HavingSpec plugins from extensions; queries built by older tooling.
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
- Must use natural comparator for column
- Ambiguous build, limit
- Ambiguous build, limitSpec
- Broadcast input number out of range
- BroadcastTablesTooLarge
AI-assisted analysis of apache/druid@9b90983fd2 (2026-09-07).
Data as JSON: /api/errors/26c1ce3cfb5b92f0.
Report an issue: GitHub.
Appendix: source
Thrown at multi-stage-query/src/main/java/org/apache/druid/msq/querykit/groupby/GroupByPostShuffleFrameProcessor.java:343
return row -> {};
}
}
@Nullable
private static HavingSpec cloneHavingSpec(final GroupByQuery query)
{
if (query.getHavingSpec() == null || query.getHavingSpec() instanceof AlwaysHavingSpec) {
return null;
} else if (query.getHavingSpec() instanceof DimFilterHavingSpec) {
final DimFilterHavingSpec dimFilterHavingSpec = (DimFilterHavingSpec) query.getHavingSpec();
final DimFilterHavingSpec clonedHavingSpec = new DimFilterHavingSpec(
dimFilterHavingSpec.getDimFilter(),
dimFilterHavingSpec.isFinalize()
);
clonedHavingSpec.setQuery(query);
return clonedHavingSpec;
} else {
throw new UnsupportedOperationException("Must use 'filter' or 'always' havingSpec");
}
}
/**
* Create virtual columns containing "bonus" fields that should be attached to the {@link FrameWriter} for
* this processor. Kept in sync with the signature generated by {@link GroupByQueryKit}.
*/
private static VirtualColumns makeVirtualColumnsForFrameWriter(
@Nullable final VirtualColumn partitionBoostVirtualColumn,
final ObjectMapper jsonMapper,
final GroupByQuery query
)
{
List<VirtualColumn> virtualColumns = new ArrayList<>();
virtualColumns.add(partitionBoostVirtualColumn);
final VirtualColumn segmentGranularityVirtualColumn =
QueryKitUtils.makeSegmentGranularityVirtualColumn(jsonMapper, query.context());View on GitHub (pinned to 9b90983fd2)