apache/druid · error · IllegalStateException

Ambiguous build, limit

Error message

Ambiguous build, limit[%s] or columnSpecs[%s] already set.

What it means

Inverse of the explicit-limitSpec check: ensureFluentLimitsNotSet throws ISE when fluent limit APIs (setLimit/addOrderByColumnSpec) were already used and an explicit limitSpec is then set on the same Builder, because the resulting limit configuration would be ambiguous.

Solutions

  1. Remove one of the two limit definitions — keep either the fluent limit or the explicit limitSpec
  2. Reset/rebuild the builder if limits from a previous stage should be discarded
  3. Check builder state (limit != Integer.MAX_VALUE or non-empty orderByColumnSpecs) before calling setLimitSpec

Example fix

// before
builder.setLimit(10).addOrderByColumnSpec(new OrderByColumnSpec("dim", ASC)).setLimitSpec(spec);
// after
builder.setLimitSpec(spec); // drop the fluent limit calls
Defensive patterns

Strategy: validation

Validate before calling

if (limit != Integer.MAX_VALUE || !orderByColumnSpecs.isEmpty()) { /* fluent limits set — do not call setLimitSpec */ }

Type guard

null

Try / catch

try { builder.setLimitSpec(spec); } catch (IllegalStateException e) { if (e.getMessage().contains("columnSpecs")) { /* clear fluent limits first */ } throw e; }

Prevention

When it happens

Trigger: Calling Builder.setLimit(...) or addOrderByColumnSpec(...) and then setLimitSpec(...) on the same builder instance.

Common situations: Programmatic query building that first applies default sorting then a caller-supplied limitSpec; framework code layering limitSpec onto pre-configured builders; deserialization edge cases.

Related errors


AI-assisted analysis of apache/druid@9b90983fd2 (2026-09-07). Data as JSON: /api/errors/6466dea928044cb5. Report an issue: GitHub.

Appendix: source

Thrown at processing/src/main/java/org/apache/druid/query/groupby/GroupByQuery.java:1132

    {
      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)
    {
      this.dimFilter = dimFilter;
      return this;
    }

    public Builder setGranularity(Granularity granularity)
    {
      this.granularity = granularity;

View on GitHub (pinned to 9b90983fd2)