{"record":{"id":"d71fc46ae4f358be","repo":"apache/druid","slug":"should-only-have-one-interval-got-s","errorCode":null,"errorMessage":"Should only have one interval, got[%s]","messagePattern":"Should only have one interval, got\\[(.+?)\\]","errorType":"validation","errorClass":"IllegalArgumentException","httpStatus":null,"severity":"error","filePath":"processing/src/main/java/org/apache/druid/query/groupby/GroupingEngine.java","lineNumber":537,"sourceCode":"      @Nullable GroupByQueryMetrics groupByQueryMetrics\n  )\n  {\n    validateForProcess(query, cursorFactory);\n    final CursorBuildSpec buildSpec = makeCursorBuildSpec(query, groupByQueryMetrics);\n    return processWithCursorHolder(query, cursorFactory, cursorHolder, timeBoundaryInspector, bufferPool, buildSpec);\n  }\n\n  private static void validateForProcess(GroupByQuery query, @Nullable CursorFactory cursorFactory)\n  {\n    if (cursorFactory == null) {\n      throw new ISE(\n          \"Null cursor factory found. Probably trying to issue a query against a segment being memory unmapped.\"\n      );\n    }\n\n    final List<Interval> intervals = query.getQuerySegmentSpec().getIntervals();\n    if (intervals.size() != 1) {\n      throw new IAE(\"Should only have one interval, got[%s]\", intervals);\n    }\n  }\n\n  private Sequence<ResultRow> processWithCursorHolder(\n      GroupByQuery query,\n      CursorFactory cursorFactory,\n      CursorHolder cursorHolder,\n      @Nullable TimeBoundaryInspector timeBoundaryInspector,\n      NonBlockingPool<ByteBuffer> bufferPool,\n      CursorBuildSpec buildSpec\n  )\n  {\n    // Register the cursor holder on the closer before any work that could throw, so a single catch path covers\n    // every cleanup scenario (bufferPool.take() failure, pipeline construction failure, etc.) and the original\n    // exception is preserved with any close errors as suppressed.\n    final Closer closer = Closer.create();\n    closer.register(cursorHolder);\n","sourceCodeStart":519,"sourceCodeEnd":555,"githubUrl":"https://github.com/apache/druid/blob/9b90983fd291f26935af934383ce360473179e4d/processing/src/main/java/org/apache/druid/query/groupby/GroupingEngine.java#L519-L555","documentation":"GroupBy processing requires the query's querySegmentSpec to contain exactly one interval. validateForProcess throws this IAE when the interval list is empty or has multiple intervals, since the cursor-holder based processing path can only iterate a single interval.","triggerScenarios":"Issuing a GroupByQuery (via GroupingEngine.process/makeCursorHolderAsync/processCursorHolder) whose getQuerySegmentSpec().getIntervals() returns a list with size != 1 — e.g. multiple explicit intervals like [\"2012-01-01/2012-01-02\",\"2012-02-01/2012-02-02\"] or none.","commonSituations":"Programmatically building a query with multiple intervals; client SDKs accepting interval arrays; migrating code from the legacy engine that accepted multiple intervals; converting SQL with disjoined time ranges.","solutions":["Issue one query per interval, or use a single covering interval","Use multipleIntervals handling at the tool/SQL layer (Druid SQL splits ranges) instead of the native groupBy v2 cursor path","Validate query.getQuerySegmentSpec().getIntervals().size() == 1 before processing","Rewrite with a union datasource of single-interval subqueries if multiple ranges are needed"],"exampleFix":"// before\nquery.setInterval(Arrays.asList(\"2022-01-01/2022-02-01\", \"2022-03-01/2022-04-01\"));\n// after\nquery.setInterval(\"2022-01-01/2022-04-01\"); // single covering interval, or split into two queries","handlingStrategy":"validation","validationCode":"List<Interval> intervals = query.getQuerySegmentSpec().getIntervals();\nif (intervals.size() != 1) {\n  throw new IAE(\"groupBy cursor path needs exactly one interval, got %d\", intervals.size());\n}","typeGuard":null,"tryCatchPattern":"try { engine.process(query, ...); } catch (IAE e) { if (e.getMessage().startsWith(\"Should only have one interval\")) { splitAndRunPerInterval(query); } else { throw e; } }","preventionTips":["Always build groupBy queries with a single interval string","Split multi-range requests into multiple queries at the client layer","Validate intervals before submitting native queries"],"tags":["druid","groupby","query-validation","intervals"],"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"}