apache/druid · error · IllegalArgumentException
WindowOperatorQuery must run on top of a query or inline…
Error message
WindowOperatorQuery must run on top of a query or inline data source, got [%s]
What it means
WindowOperatorQuery.validateMaybeRewriteDataSource requires the query's data source to be either a query data source (with a sub-query) or an InlineDataSource, since window operators run on materialized rows. Any other data source type (e.g. a bare table datasource) is rejected with this IAE.
Solutions
- Wrap the data source in a QueryDataSource (e.g. a ScanQuery/TableScan) so the window operator reads from a sub-query
- Use an InlineDataSource for small pre-materialized inputs
- Fix the query rewrite/translation layer that constructs WindowOperatorQuery to always emit query or inline sources
Example fix
// before new WindowOperatorQuery(tableDataSource, ...) // after new WindowOperatorQuery( new QueryDataSource(newScanQueryBuilder().dataSource(tableDataSource).build()), ...)
Defensive patterns
Strategy: validation
Validate before calling
DataSource ds = query.getDataSource();
if (!(ds instanceof QueryDataSource) && !(ds instanceof InlineDataSource)) {
throw new IllegalArgumentException("WindowOperatorQuery needs query/inline source, got " + ds.getClass());
} Type guard
boolean isValidWindowSource(DataSource ds) {
return ds instanceof QueryDataSource || ds instanceof InlineDataSource;
} Try / catch
try {
windowOperatorQuery.validateMaybeRewriteDataSource(dataSource);
} catch (IAE e) {
if (e.getMessage().startsWith("WindowOperatorQuery must run on top of")) {
dataSource = new QueryDataSource(scanQueryOver(dataSource));
} else throw e;
} Prevention
- Always wrap base datasources (table etc.) in a QueryDataSource when building window operator queries
- Use InlineDataSource only for small, already-materialized inputs
- Add unit tests for native window query builders to assert the data source type before construction
When it happens
Trigger: Constructing a WindowOperatorQuery (or running a window-function native query) whose DataSource is directly a table/lookup/etc. rather than a query or inline source.
Common situations: Hand-built native window queries pointing at a table datasource without an intermediate scan/query, or tooling that rewrites SQL window queries to native but fails to insert the base query layer.
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
- A local input source accepts only one of
- A local input source can set parameter
- A local input source requires one parameter of
- A local input source requires one property of
- A table definition must include a table spec.
AI-assisted analysis of apache/druid@9b90983fd2 (2026-09-07).
Data as JSON: /api/errors/6c08f3286e16b70c.
Report an issue: GitHub.
Appendix: source
Thrown at processing/src/main/java/org/apache/druid/query/operator/WindowOperatorQuery.java:81
// We can re-write scan-style sub queries into an operator instead of doing the actual Scan query. So, we
// check for that and, if we are going to do the rewrite, then we return the sub datasource such that the
// parent constructor in BaseQuery stores the actual data source that we want to be distributed to.
// At this point, we could also reach into a QueryDataSource and validate that the ordering expected by the
// partitioning at least aligns with the ordering coming from the underlying query. We unfortunately don't
// have enough information to validate that the underlying ordering aligns with expectations for the actual
// window operator queries, but maybe we could get that and validate it here too.
if (dataSource instanceof QueryDataSource) {
final Query<?> subQuery = ((QueryDataSource) dataSource).getQuery();
if (subQuery instanceof ScanQuery) {
return subQuery.getDataSource();
}
return dataSource;
} else if (dataSource instanceof InlineDataSource) {
return dataSource;
} else {
throw new IAE("WindowOperatorQuery must run on top of a query or inline data source, got [%s]", dataSource);
}
}
private final RowSignature rowSignature;
private final List<OperatorFactory> operators;
private final List<OperatorFactory> leafOperators;
@JsonCreator
public WindowOperatorQuery(
@JsonProperty("dataSource") DataSource dataSource,
@JsonProperty("intervals") QuerySegmentSpec intervals,
@JsonProperty("context") Map<String, Object> context,
@JsonProperty("outputSignature") RowSignature rowSignature,
@JsonProperty("operatorDefinition") List<OperatorFactory> operators,
@JsonProperty("leafOperators") List<OperatorFactory> leafOperators
)
{
super(View on GitHub (pinned to 9b90983fd2)