{"record":{"id":"7c12da4bb52aa14d","repo":"apache/druid","slug":"when-forcing-limit-push-down-the-provided-limit-s","errorCode":null,"errorMessage":"When forcing limit push down, the provided limit spec must have a limit.","messagePattern":"When forcing limit push down, the provided limit spec must have a limit\\.","errorType":"validation","errorClass":"IllegalArgumentException","httpStatus":null,"severity":"error","filePath":"processing/src/main/java/org/apache/druid/query/groupby/GroupByQuery.java","lineNumber":510,"sourceCode":"            return rowOrdering.compare((ResultRow) lhs, (ResultRow) rhs);\n          } else {\n            //noinspection unchecked (Probably bySegment queries; see BySegmentQueryRunner for details)\n            return ((Ordering) Comparators.naturalNullsFirst()).compare(lhs, rhs);\n          }\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();","sourceCodeStart":492,"sourceCodeEnd":528,"githubUrl":"https://github.com/apache/druid/blob/9b90983fd291f26935af934383ce360473179e4d/processing/src/main/java/org/apache/druid/query/groupby/GroupByQuery.java#L492-L528","documentation":"With forceLimitPushDown=true, the provided DefaultLimitSpec must actually impose a limit (isLimited()); a spec with only sort orderings, or with Integer.MAX_VALUE limit, cannot be pushed down, so validateAndGetForceLimitPushDown throws IAE.","triggerScenarios":"forceLimitPushDown=true combined with a DefaultLimitSpec whose limit is not set/meaningful (e.g. limitSpec containing only orderBy columns, or limit <= 0 / MAX_VALUE per isLimited).","commonSituations":"Builders that use DefaultLimitSpec purely for sorting (order-by only); SQL queries with ORDER BY but no LIMIT compiled to an order-only limit spec while the context forces push down.","solutions":["Set an actual numeric limit on the DefaultLimitSpec (e.g. new DefaultLimitSpec(orderings, someLimit)).","Disable forceLimitPushDown when the query only sorts without limiting.","Check DefaultLimitSpec.isLimited() before enabling the flag in programmatic query construction."],"exampleFix":"// before\ncontext.put(\"forceLimitPushDown\", true);\nquery.withLimitSpec(new DefaultLimitSpec(orderings, Integer.MAX_VALUE));\n// after\ncontext.put(\"forceLimitPushDown\", true);\nquery.withLimitSpec(new DefaultLimitSpec(orderings, 100)); // an actual limit","handlingStrategy":"validation","validationCode":"boolean ok = !forcePushDown || (query.getLimitSpec() instanceof DefaultLimitSpec && ((DefaultLimitSpec) query.getLimitSpec()).isLimited());","typeGuard":"boolean limitable = (ls instanceof DefaultLimitSpec) && ((DefaultLimitSpec) ls).isLimited();","tryCatchPattern":"try { query.validateAndGetForceLimitPushDown(); } catch (IllegalArgumentException e) { /* set a real limit or remove the flag */ }","preventionTips":["Ensure limitSpec has a finite limit, not just orderings","Call DefaultLimitSpec.isLimited() as a pre-check","Avoid using DefaultLimitSpec purely for sorting when forcing push down"],"tags":["druid","groupby","limit-pushdown","query-context"],"backgroundTag":"invalid-argument-value","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"}