apache/druid · error · IllegalStateException

Unspecified interval

Error message

Unspecified interval[%s] in granularitySpec[%s]

What it means

After resolving the bucket interval for a timestamp, findIntervalAndVersion checks that the interval is actually part of the granularitySpec's materialized bucket intervals. If the bucketed interval is somehow not among the explicitly specified intervals, the internal invariant between bucketing and the spec is broken, so it throws this ISE. This normally indicates a spec inconsistency rather than a data problem.

Solutions

  1. Regenerate or correct granularitySpec so that explicit intervals are exact multiples/alignments of segmentGranularity buckets.
  2. Rewrite the spec from scratch (or via the UI/wizard) instead of hand-editing intervals.
  3. Check the Druid version for known bugs in bucket interval materialization; upgrade if affected.
  4. If you don't need explicit intervals, omit them so Druid derives intervals from data timestamps.

Example fix

// before
"segmentGranularity":"day", "intervals":["2024-01-01T12:00/2024-01-02"]  // misaligned
// after
"segmentGranularity":"day", "intervals":["2024-01-01/2024-01-02"]
Defensive patterns

Strategy: validation

Validate before calling

// verify every bucket of the explicit intervals aligns with segmentGranularity
for (Interval i : granularitySpec.getQuery().getIntervals()) {
  Interval bucket = granularitySpec.getSegmentGranularity().bucket(i.getStart());
  if (!i.equals(bucket.getStart(), i.getEnd())) {
    throw new IllegalArgumentException("Interval " + i + " not aligned with segmentGranularity");
  }
}

Try / catch

try {
  ingest(spec);
} catch (IllegalStateException e) {
  if (e.getMessage().startsWith("Unspecified interval")) {
    // regenerate the granularitySpec with correctly aligned intervals
  } else throw e;
}

Prevention

When it happens

Trigger: Explicit-interval granularitySpec where bucketInterval(timestamp) returns an interval that is not contained in the materialized bucket intervals — a spec/state mismatch, e.g. intervals list misaligned with segmentGranularity boundaries after spec edits or upgrades.

Common situations: Hand-edited ingestion specs with intervals not aligned to segment granularity; Druid version upgrades changing bucket interval materialization; custom granularity specs built programmatically with inconsistent intervals.

Understand the failure class

Background: "This is a bug, please report it": internal invariant violations, unreachable panics, and SNH errors explained — this error's family across 47 libraries.

Related errors


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

Appendix: source

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

      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) {
          final int maxAllowedLockCount = ((ParallelIndexTuningConfig) ingestionSpec.getTuningConfig())
              .getMaxAllowedLockCount();
          if (maxAllowedLockCount >= 0 && locks.size() >= maxAllowedLockCount) {
            throw new MaxAllowedLocksExceededException(maxAllowedLockCount);
          }

View on GitHub (pinned to 9b90983fd2)