apache/druid · error · IllegalArgumentException

Cannot force limit push down when a having spec is present.

Error message

Cannot force limit push down when a having spec is present.

What it means

GroupByQuery.validateAndGetForceLimitPushDown rejects forcing limit push down when the query has a havingSpec. Limit push down moves the limit/sort into the group-by engine itself, which cannot coexist with a HAVING filter, so the query throws IAE rather than silently producing wrong results.

Solutions

  1. Remove the havingSpec from the query, or drop the force-limit-push-down context flag
  2. Apply the HAVING filter in an outer wrapper query and keep limit push down on the inner group-by
  3. If using SQL, rewrite the query so HAVING is applied by a separate aggregation level

Example fix

// before
GroupByQuery q = orig.withOverriddenContext(ImmutableMap.of("applyLimitPushDown", true)); // has havingSpec
// after
GroupByQuery q = orig.withOverriddenContext(ImmutableMap.of("applyLimitPushDown", false)); // or remove havingSpec
Defensive patterns

Strategy: validation

Validate before calling

if (query.getHavingSpec() != null && Boolean.TRUE.equals(query.getContextValue("applyLimitPushDown"))) { throw new IllegalArgumentException("Disable limit push down when a havingSpec is present"); }

Type guard

boolean canForceLimitPushDown(GroupByQuery q) { return q.getHavingSpec() == null; }

Try / catch

try { return isApplyLimitPushDown(query, forcePushDown); } catch (IllegalArgumentException e) { log.warn(e, "Falling back to no limit push down"); return false; }

Prevention

When it happens

Trigger: Setting context key 'applyLimitPushDown' (or useCache/broker forcing) to true on a GroupByQuery whose Builder.setHavingSpec(...) was called; isApplyLimitPushDown then calls validateAndGetForceLimitPushDown and throws.

Common situations: Users enable limit push down for performance while also using SQL HAVING clauses or havingSpecs configured via the native API; SQL planner-generated queries with HAVING translated to a havingSpec.

Related errors


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

Appendix: source

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

          }
        }
    );
  }

  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;
  }

  private RowSignature computeResultRowSignature(final RowSignature.Finalization finalization)
  {
    final RowSignature.Builder builder = RowSignature.builder();

    if (universalTimestamp == null) {
      builder.addTimeColumn();
    }

View on GitHub (pinned to 9b90983fd2)