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
- Compute dataInterval to fully enclose index.getMinTime()/getMaxTime() (e.g. pad to segment granularity) before persisting
- Fix timestamp parsing/timezone handling so events land in the expected interval
- 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
- Derive dataInterval from actual min/max timestamps, not the requested query window
- Normalize timestamps to UTC before adding to the index
- Validate timestamp parsing/timezone config in ingestion specs
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
- Could not find interval for timestamp
- Failed to get shardSpec for interval
- Indices to merge contained metric
- Trying to persist an empty index!
- A-Not-B requires at least 1 sketch
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)