{"record":{"id":"20f9c48869928264","repo":"apache/druid","slug":"cannot-force-limit-push-down-when-a-having-spec-is","errorCode":null,"errorMessage":"Cannot force limit push down when a having spec is present.","messagePattern":"Cannot force limit push down when a having spec is present\\.","errorType":"validation","errorClass":"IllegalArgumentException","httpStatus":null,"severity":"error","filePath":"processing/src/main/java/org/apache/druid/query/groupby/GroupByQuery.java","lineNumber":514,"sourceCode":"          }\n        }\n    );\n  }\n\n  private boolean validateAndGetForceLimitPushDown()\n  {\n    final boolean forcePushDown = context().getBoolean(GroupByQueryConfig.CTX_KEY_FORCE_LIMIT_PUSH_DOWN, false);\n    if (forcePushDown) {\n      if (!(limitSpec instanceof DefaultLimitSpec)) {\n        throw new IAE(\"When forcing limit push down, a limit spec must be provided.\");\n      }\n\n      if (!((DefaultLimitSpec) limitSpec).isLimited()) {\n        throw new IAE(\"When forcing limit push down, the provided limit spec must have a limit.\");\n      }\n\n      if (havingSpec != null) {\n        throw new IAE(\"Cannot force limit push down when a having spec is present.\");\n      }\n\n      for (OrderByColumnSpec orderBySpec : ((DefaultLimitSpec) limitSpec).getColumns()) {\n        if (OrderByColumnSpec.getPostAggIndexForOrderBy(orderBySpec, postAggregatorSpecs) > -1) {\n          throw new UnsupportedOperationException(\"Limit push down when sorting by a post aggregator is not supported.\");\n        }\n      }\n    }\n    return forcePushDown;\n  }\n\n  private RowSignature computeResultRowSignature(final RowSignature.Finalization finalization)\n  {\n    final RowSignature.Builder builder = RowSignature.builder();\n\n    if (universalTimestamp == null) {\n      builder.addTimeColumn();\n    }","sourceCodeStart":496,"sourceCodeEnd":532,"githubUrl":"https://github.com/apache/druid/blob/9b90983fd291f26935af934383ce360473179e4d/processing/src/main/java/org/apache/druid/query/groupby/GroupByQuery.java#L496-L532","documentation":"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.","triggerScenarios":"Setting context key 'applyLimitPushDown' (or useCache/broker forcing) to true on a GroupByQuery whose Builder.setHavingSpec(...) was called; isApplyLimitPushDown then calls validateAndGetForceLimitPushDown and throws.","commonSituations":"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.","solutions":["Remove the havingSpec from the query, or drop the force-limit-push-down context flag","Apply the HAVING filter in an outer wrapper query and keep limit push down on the inner group-by","If using SQL, rewrite the query so HAVING is applied by a separate aggregation level"],"exampleFix":"// before\nGroupByQuery q = orig.withOverriddenContext(ImmutableMap.of(\"applyLimitPushDown\", true)); // has havingSpec\n// after\nGroupByQuery q = orig.withOverriddenContext(ImmutableMap.of(\"applyLimitPushDown\", false)); // or remove havingSpec","handlingStrategy":"validation","validationCode":"if (query.getHavingSpec() != null && Boolean.TRUE.equals(query.getContextValue(\"applyLimitPushDown\"))) { throw new IllegalArgumentException(\"Disable limit push down when a havingSpec is present\"); }","typeGuard":"boolean canForceLimitPushDown(GroupByQuery q) { return q.getHavingSpec() == null; }","tryCatchPattern":"try { return isApplyLimitPushDown(query, forcePushDown); } catch (IllegalArgumentException e) { log.warn(e, \"Falling back to no limit push down\"); return false; }","preventionTips":["Check havingSpec before enabling applyLimitPushDown context","Encapsulate limit-push-down enabling in a helper that validates query features"],"tags":["groupby","limit-push-down","invalid-argument-value"],"backgroundTag":"mutually-exclusive-options","analyzedSha":"9b90983fd291f26935af934383ce360473179e4d","analyzedAt":"2026-09-07T13:32:30.957Z","contentChangedAt":"2026-09-07T13:32:30.957Z","schemaVersion":2},"datasetVersion":"2026-09-17T15:17:12.973Z"}