apache/druid · error · IllegalArgumentException

When forcing limit push down, a limit spec must be provided.

Error message

When forcing limit push down, a limit spec must be provided.

What it means

When the query context forces limit push down (forceLimitPushDown=true), GroupByQuery requires a DefaultLimitSpec so limits can be pushed into the segment-level processing. validateAndGetForceLimitPushDown throws IAE if the limitSpec is missing or of the wrong type.

Solutions

  1. Provide a DefaultLimitSpec with columns and a limit in the query when forceLimitPushDown is enabled.
  2. Remove the forceLimitPushDown context flag so the query runs without forced push down.
  3. Verify the limitSpec is DefaultLimitSpec (cast-check) before enabling the flag in query-building code.

Example fix

// before
context.put("forceLimitPushDown", true); // query has no limitSpec
// after
context.put("forceLimitPushDown", true);
query = query.withLimitSpec(new DefaultLimitSpec(ImmutableList.of(new OrderByColumnSpec("dim", ASC)), 100));
Defensive patterns

Strategy: validation

Validate before calling

boolean ok = !forcePushDown || (query.getLimitSpec() instanceof DefaultLimitSpec);

Type guard

boolean hasDefaultLimitSpec = query.getLimitSpec() instanceof DefaultLimitSpec;

Try / catch

try { query.validateAndGetForceLimitPushDown(); } catch (IllegalArgumentException e) { /* add limit spec or drop the flag */ }

Prevention

When it happens

Trigger: Setting context key forceLimitPushDown=true while limitSpec is null or is a non-DefaultLimitSpec implementation (e.g. NoopLimitSpec).

Common situations: Users enabling forceLimitPushDown in query context for performance without specifying a limit; programmatic query builders that omit limitSpec; queries where SQL planner strips the limit.

Understand the failure class

Background: "missing required argument" and "the following required arguments were not provided": what required-argument errors mean and how to fix them — this error's family across 20 libraries.

Related errors


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

Appendix: source

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

    return Ordering.from(
        (lhs, rhs) -> {
          if (lhs instanceof ResultRow) {
            return rowOrdering.compare((ResultRow) lhs, (ResultRow) rhs);
          } else {
            //noinspection unchecked (Probably bySegment queries; see BySegmentQueryRunner for details)
            return ((Ordering) Comparators.naturalNullsFirst()).compare(lhs, rhs);
          }
        }
    );
  }

  private boolean validateAndGetForceLimitPushDown()
  {
    final boolean forcePushDown = context().getBoolean(GroupByQueryConfig.CTX_KEY_FORCE_LIMIT_PUSH_DOWN, false);
    if (forcePushDown) {
      if (!(limitSpec instanceof DefaultLimitSpec)) {
        throw new IAE("When forcing limit push down, a limit spec must be provided.");
      }

      if (!((DefaultLimitSpec) limitSpec).isLimited()) {
        throw new IAE("When forcing limit push down, the provided limit spec must have a limit.");
      }

      if (havingSpec != null) {
        throw new IAE("Cannot force limit push down when a having spec is present.");
      }

      for (OrderByColumnSpec orderBySpec : ((DefaultLimitSpec) limitSpec).getColumns()) {
        if (OrderByColumnSpec.getPostAggIndexForOrderBy(orderBySpec, postAggregatorSpecs) > -1) {
          throw new UnsupportedOperationException("Limit push down when sorting by a post aggregator is not supported.");
        }
      }
    }
    return forcePushDown;
  }

View on GitHub (pinned to 9b90983fd2)