apache/druid · error · IllegalStateException
Ambiguous build, limitSpec
Error message
Ambiguous build, limitSpec[%s] already set
What it means
GroupByQuery.Builder supports two ways to specify limits: setLimitSpec(...) and the fluent setLimit()/addOrderByColumnSpec() API. Using both is ambiguous, so ensureExplicitLimitSpecNotSet throws ISE when an explicit limitSpec is already set and fluent limit methods are then used.
Solutions
- Pick one API: use only setLimitSpec OR only the fluent setLimit/addOrderByColumnSpec methods
- Before fluent calls, guard with hasFluentization-like checks or clear the existing limitSpec
- Remove the redundant setLimitSpec call when fluent limits already encode the desired limit/sort
Example fix
// before builder.setLimitSpec(limitSpec).setLimit(10); // after builder.setLimitSpec(limitSpec); // or: builder.setLimit(10).addOrderByColumnSpec(...);
Defensive patterns
Strategy: validation
Validate before calling
if (builder != null && explicitLimitSpecSet && fluentLimitUsed) throw new IllegalStateException("Use either setLimitSpec or fluent limit APIs, not both"); Type guard
null
Try / catch
try { builder.build(); } catch (IllegalStateException e) { if (e.getMessage().startsWith("Ambiguous build")) { /* choose one limit mechanism and rebuild */ } throw e; } Prevention
- Standardize on one limit API (prefer setLimitSpec) across your query-building code
- Do not mutate builders after passing limitSpec through constructors/factories
When it happens
Trigger: Calling Builder.setLimitSpec(...) (or limitSpec field set) and subsequently calling setLimit/addOrderByColumnSpec/limit-fluent methods on the same builder.
Common situations: Query-builder code mixing legacy limitSpec JSON with newer fluent API calls; deserialization followed by programmatic limit modification; refactor leftovers.
Related errors
- Ambiguous build, limit
- buffer for list is too small, was
- Cannot force limit push down when a having spec is present.
- Duplicate output name
- Group key should be a single dimension
AI-assisted analysis of apache/druid@9b90983fd2 (2026-09-07).
Data as JSON: /api/errors/cfedde221a87cbf0.
Report an issue: GitHub.
Appendix: source
Thrown at processing/src/main/java/org/apache/druid/query/groupby/GroupByQuery.java:1125
ensureExplicitLimitSpecNotSet();
this.orderByColumnSpecs = new ArrayList<>(columnSpec);
this.postProcessingFn = null;
return this;
}
public Builder setLimitSpec(LimitSpec limitSpec)
{
Preconditions.checkNotNull(limitSpec);
ensureFluentLimitsNotSet();
this.limitSpec = limitSpec;
this.postProcessingFn = null;
return this;
}
private void ensureExplicitLimitSpecNotSet()
{
if (limitSpec != null) {
throw new ISE("Ambiguous build, limitSpec[%s] already set", limitSpec);
}
}
private void ensureFluentLimitsNotSet()
{
if (!(limit == Integer.MAX_VALUE && orderByColumnSpecs.isEmpty())) {
throw new ISE("Ambiguous build, limit[%s] or columnSpecs[%s] already set.", limit, orderByColumnSpecs);
}
}
public Builder setQuerySegmentSpec(QuerySegmentSpec querySegmentSpec)
{
this.querySegmentSpec = querySegmentSpec;
return this;
}
public Builder setDimFilter(@Nullable DimFilter dimFilter)
{View on GitHub (pinned to 9b90983fd2)