apache/druid · error · IllegalArgumentException

interval[ ] does not encapsulate the full range of…

Error message

interval[%s] does not encapsulate the full range of timestamps[%s, %s]

What it means

persist verifies that the caller-supplied dataInterval fully covers the index's actual min and max timestamps. If any row falls outside the declared interval, the resulting segment's metadata would be wrong, so Druid throws IAE. This protects segment interval invariants used by the coordinator and query planning.

Solutions

  1. Compute dataInterval to fully enclose index.getMinTime()/getMaxTime() (e.g. pad to segment granularity) before persisting
  2. Fix timestamp parsing/timezone handling so events land in the expected interval
  3. Sanitize or reject out-of-window events at ingestion instead of relying on the interval to clip them

Example fix

// before
Interval interval = new Interval("2024-01-01/2024-01-02");
merger.persist(index, interval, outDir, indexSpec, progress, null);
// after
Interval interval = new Interval(
    index.getMinTime().toString().substring(0, 10),
    index.getMaxTime().plusDays(1).toString().substring(0, 10));
if (interval.contains(index.getMinTime()) && interval.contains(index.getMaxTime())) {
  merger.persist(index, interval, outDir, indexSpec, progress, null);
}
Defensive patterns

Strategy: validation

Validate before calling

Interval safe = new Interval(
    index.getMinTime().toString(), index.getMaxTime().plusMillis(1).toString());
if (!dataInterval.contains(index.getMinTime())
    || !dataInterval.contains(index.getMaxTime())) {
  throw new IllegalStateException("dataInterval " + dataInterval
      + " does not cover [" + index.getMinTime() + ", " + index.getMaxTime() + "]");
}

Try / catch

try {
  merger.persist(index, dataInterval, outDir, indexSpec, progress, null);
} catch (IAE e) {
  if (e.getMessage().contains("does not encapsulate")) {
    // widen dataInterval to cover actual timestamps and retry
  }
}

Prevention

When it happens

Trigger: Calling persist with a dataInterval that starts after index.getMinTime() or ends before index.getMaxTime() — e.g. event timestamps outside the configured segment granularity window, often due to timezone or UTC-offset mistakes.

Common situations: Rolling windows with events arriving outside the shard interval; timestamp parsing that misreads timezone offsets; hand-rolled ingestion code that computes dataInterval from the query range rather than actual data.

Understand the failure class

Background: "Must be a positive integer", "Invalid value", "Unsupported": the invalid-argument-value error family, when a library rejects the value you pass — this error's family across 35 libraries.

Related errors


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

Appendix: source

Thrown at processing/src/main/java/org/apache/druid/segment/IndexMergerBase.java:143

  public File persist(
      final IncrementalIndex index,
      final Interval dataInterval,
      File outDir,
      IndexSpec indexSpec,
      ProgressIndicator progress,
      @Nullable SegmentWriteOutMediumFactory segmentWriteOutMediumFactory
  ) throws IOException
  {
    if (index.isEmpty()) {
      throw new IAE("Trying to persist an empty index!");
    }

    indexSpec = indexSpec.getEffectiveSpec();

    final DateTime firstTimestamp = index.getMinTime();
    final DateTime lastTimestamp = index.getMaxTime();
    if (!(dataInterval.contains(firstTimestamp) && dataInterval.contains(lastTimestamp))) {
      throw new IAE(
          "interval[%s] does not encapsulate the full range of timestamps[%s, %s]",
          dataInterval,
          firstTimestamp,
          lastTimestamp
      );
    }

    FileUtils.mkdirp(outDir);

    log.debug("Starting persist for interval[%s], rows[%,d]", dataInterval, index.numRows());
    return multiphaseMerge(
        Collections.singletonList(
            new IncrementalIndexAdapter(
                dataInterval,
                index,
                indexSpec.getBitmapSerdeFactory().getBitmapFactory()
            )
        ),

View on GitHub (pinned to 9b90983fd2)