apache/druid · error · IllegalArgumentException

Could not find interval for timestamp

Error message

Could not find interval for timestamp [%s]

What it means

When the granularitySpec has explicit intervals (materializedBucketIntervals non-empty), findIntervalAndVersion uses bucketInterval(timestamp) to find the bucketed interval containing the record's timestamp. If the timestamp falls outside all explicitly configured intervals, no bucket exists and this IAE is thrown. Druid refuses to write data outside the declared ingestion window.

Solutions

  1. Widen granularitySpec.intervals to cover all timestamps present in the input data.
  2. Filter or route out-of-range records before ingestion (e.g. with a transform or pre-filter) so out-of-window rows are dropped explicitly.
  3. Use windowing (drop/fixed/partial) tuning to handle late data instead of failing, where supported.
  4. Check timestamp parsing/timezone config to confirm timestamps are interpreted as intended.

Example fix

// before
"intervals": ["2024-01-01/2024-01-02"]  // data has events on 2024-01-03
// after
"intervals": ["2024-01-01/2024-01-04"]
Defensive patterns

Strategy: validation

Validate before calling

DateTime ts = row.getTimestamp();
List<Interval> intervals = granularitySpec.getQuery().getIntervals();
boolean inRange = intervals.stream().anyMatch(i -> i.contains(ts));
if (!inRange) throw new IllegalArgumentException("Timestamp " + ts + " outside configured intervals");

Try / catch

try {
  ingest(records);
} catch (IAE e) {
  if (e.getMessage().startsWith("Could not find interval for timestamp")) {
    // widen intervals or drop the out-of-window record and resume
  } else throw e;
}

Prevention

When it happens

Trigger: Ingesting records whose event timestamp is not contained by any interval listed in granularitySpec.intervals during a batch task with explicit intervals.

Common situations: intervals configured too narrowly while source data contains older/newer events; timezone confusion shifting timestamps outside the range; data drift after the ingestion spec was written; time zone in timestamps misparsed (UTC vs local).

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/5b5083c6eef39c85. Report an issue: GitHub.

Appendix: source

Thrown at indexing-service/src/main/java/org/apache/druid/indexing/common/task/AbstractBatchIndexTask.java:826

    final List<TaskLock> locks = toolbox
        .getTaskActionClient()
        .submit(new LockListAction());
    final TaskLock revokedLock = locks.stream().filter(TaskLock::isRevoked).findAny().orElse(null);
    if (revokedLock != null) {
      throw new ISE("Lock revoked: [%s]", revokedLock);
    }
    final Map<Interval, String> versions = locks.stream().collect(
        Collectors.toMap(TaskLock::getInterval, TaskLock::getVersion)
    );

    final Interval interval;
    final String version;
    if (!materializedBucketIntervals.isEmpty()) {
      // If granularity spec has explicit intervals, we just need to find the version associated to the interval.
      // This is because we should have gotten all required locks up front when the task starts up.
      final Optional<Interval> maybeInterval = granularitySpec.bucketInterval(timestamp);
      if (!maybeInterval.isPresent()) {
        throw new IAE("Could not find interval for timestamp [%s]", timestamp);
      }

      interval = maybeInterval.get();
      if (!materializedBucketIntervals.contains(interval)) {
        throw new ISE("Unspecified interval[%s] in granularitySpec[%s]", interval, granularitySpec);
      }

      version = AbstractBatchIndexTask.findVersion(versions, interval);
      if (version == null) {
        throw new ISE("Cannot find a version for interval[%s]", interval);
      }
    } else {
      // We don't have explicit intervals. We can use the segment granularity to figure out what
      // interval we need, but we might not have already locked it.
      interval = granularitySpec.getSegmentGranularity().bucket(timestamp);
      final String existingLockVersion = AbstractBatchIndexTask.findVersion(versions, interval);
      if (existingLockVersion == null) {
        if (ingestionSpec.getTuningConfig() instanceof ParallelIndexTuningConfig) {

View on GitHub (pinned to 9b90983fd2)