{"record":{"id":"938217ea10939539","repo":"apache/druid","slug":"interval-s-is-empty-must-specify-a-nonempty-int","errorCode":null,"errorMessage":"Interval[%s] is empty, must specify a nonempty interval","messagePattern":"Interval\\[(.+?)\\] is empty, must specify a nonempty interval","errorType":"validation","errorClass":"IllegalArgumentException","httpStatus":null,"severity":"error","filePath":"indexing-service/src/main/java/org/apache/druid/indexing/common/task/CompactionIntervalSpec.java","lineNumber":54,"sourceCode":"/**\n * Specifying an interval to compact. A hash of the segment IDs can be optionally provided for segment validation.\n */\npublic class CompactionIntervalSpec implements CompactionInputSpec\n{\n  public static final String TYPE = \"interval\";\n\n  private final Interval interval;\n  @Nullable\n  private final String sha256OfSortedSegmentIds;\n\n  @JsonCreator\n  public CompactionIntervalSpec(\n      @JsonProperty(\"interval\") Interval interval,\n      @JsonProperty(\"sha256OfSortedSegmentIds\") @Nullable String sha256OfSortedSegmentIds\n  )\n  {\n    if (interval != null && interval.toDurationMillis() == 0) {\n      throw new IAE(\"Interval[%s] is empty, must specify a nonempty interval\", interval);\n    }\n    this.interval = interval;\n    this.sha256OfSortedSegmentIds = sha256OfSortedSegmentIds;\n  }\n\n  @JsonProperty\n  public Interval getInterval()\n  {\n    return interval;\n  }\n\n  @Nullable\n  @JsonProperty\n  public String getSha256OfSortedSegmentIds()\n  {\n    return sha256OfSortedSegmentIds;\n  }\n","sourceCodeStart":36,"sourceCodeEnd":72,"githubUrl":"https://github.com/apache/druid/blob/9b90983fd291f26935af934383ce360473179e4d/indexing-service/src/main/java/org/apache/druid/indexing/common/task/CompactionIntervalSpec.java#L36-L72","documentation":"CompactionIntervalSpec constructor rejects an Interval whose duration is exactly zero. A zero-length interval selects no segments, so Druid throws IAE at spec-construction/deserialization time rather than launching a pointless compaction task.","triggerScenarios":"Deserializing a compaction config where \"interval\" is like \"2023-01-01/2023-01-01\"; programmatically computing start==end intervals; passing an empty/null-derived interval built from two identical timestamps.","commonSituations":"Templates where interval start/end are filled from the same variable; time-boundary computation returning equal boundaries for empty data ranges; typos in ISO interval strings.","solutions":["Widen the interval so end is strictly after start (e.g., \"2023-01-01/2024-01-01\").","Check upstream code that computes start/end timestamps and guard against equal values before constructing the spec.","If the intent was 'all data', omit the interval or use the datasource's full range instead."],"exampleFix":"// before\n\"interval\": \"2023-01-01T00:00:00Z/2023-01-01T00:00:00Z\"\n// after\n\"interval\": \"2023-01-01T00:00:00Z/2023-02-01T00:00:00Z\"","handlingStrategy":"validation","validationCode":"if (interval != null && interval.toDurationMillis() == 0) throw new IllegalArgumentException(\"interval must be nonempty: \" + interval);","typeGuard":null,"tryCatchPattern":"try { new CompactionIntervalSpec(interval, hash); } catch (IAE e) { if (e.getMessage().contains(\"is empty\")) { widen interval; } else throw e; }","preventionTips":["Validate start.isBefore(end) wherever intervals are computed programmatically.","Beware timestamp truncation producing equal boundaries for empty ranges.","Prefer omitting the interval field over passing a degenerate interval."],"tags":["druid","compaction","config","validation"],"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-14T11:17:12.474Z"}