apache/druid · error · ISE

Found different granularities in segments %s

Error message

Found different granularities in segments %s

What it means

Thrown by TaskLockHelper.verifySegmentGranularity when AbstractBatchIndexTask.findGranularityFromSegments returns null, meaning the input segments passed to a segment-lock batch/compaction task do not share a single inferable segment granularity. The helper must establish one known granularity before locking existing segments for overwrite; if segments in the batch disagree on granularity, none can be inferred and the task aborts. This guard ensures output segments can overshadow all input segments consistently.

Source

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

              knownSegmentGranularity,
              segments
          );
        }
        final List<DataSegment> nonAlignedSegments = segments
            .stream()
            .filter(segment -> !knownSegmentGranularity.isAligned(segment.getInterval()))
            .collect(Collectors.toList());

        if (!nonAlignedSegments.isEmpty()) {
          throw new ISE(
              "Non-aligned segments %s for granularity[%s]",
              SegmentUtils.commaSeparatedIdentifiers(nonAlignedSegments),
              knownSegmentGranularity
          );
        }
      }
    } else {
      throw new ISE(
          "Found different granularities in segments %s",
          SegmentUtils.commaSeparatedIdentifiers(segments)
      );
    }
  }

  private boolean tryLockSegments(TaskActionClient actionClient, List<DataSegment> segments) throws IOException
  {
    final Map<Interval, List<DataSegment>> intervalToSegments = SegmentUtils.groupSegmentsByInterval(segments);
    for (Entry<Interval, List<DataSegment>> entry : intervalToSegments.entrySet()) {
      final Interval interval = entry.getKey();
      final List<DataSegment> segmentsInInterval = entry.getValue();
      final boolean hasSameVersion = segmentsInInterval
          .stream()
          .allMatch(segment -> segment.getVersion().equals(segmentsInInterval.get(0).getVersion()));
      Preconditions.checkState(
          hasSameVersion,
          "Segments %s should have same version",

View on GitHub (pinned to 9b90983fd2)

Solutions

  1. Set the compaction/batch task input to segments sharing one granularity (filter by interval so all segments align to a single period).
  2. If granularities differ intentionally, run separate compaction/overwrite tasks per granularity group.
  3. Unify the datasource granularity by re-ingesting or compacting so all segments share the same segmentGranularity going forward.
  4. Check the task's granularitySpec/segmentGranularity config matches the granularity actually present in the input segments.

Example fix

// before: mixed segments fed to one compaction task
List<DataSegment> segments = getSegments(ds); // contains day- and hour-granular segments
helper.verifyAndLockExistingSegments(client, segments);

// after: group by inferred granularity and compact each group separately
Map<Granularity, List<DataSegment>> byGran = groupByGranularity(getSegments(ds));
byGran.values().forEach(g -> helper.verifyAndLockExistingSegments(client, g));
Defensive patterns

Strategy: validation

Validate before calling

// Java: verify all segments infer to one granularity before submitting the task
Granularity g = AbstractBatchIndexTask.findGranularityFromSegments(inputSegments);
if (g == null) {
  throw new IllegalStateException("Input segments span multiple granularities; split the batch by granularity");
}

Try / catch

try {
  taskClient.runCompaction(ds, interval);
} catch (IllegalStateException e) {
  if (e.getMessage().contains("Found different granularities")) {
    // split input segments by granularity and run one task per group
  } else { throw e; }
}

Prevention

When it happens

Trigger: verifyAndLockExistingSegments -> verifySegmentGranularity with a list of existing segments whose intervals imply more than one granularity (e.g. a mix of 'day' and 'hour' aligned segments, or segments spanning inconsistent interval boundaries).

Common situations: Compaction or batch overwrite configured against a datasource whose segments were ingested with different segmentGranularity settings over time (e.g. historical data at 'month', newer data at 'day'); manual segment lists assembled from mixed intervals; retuning granularitySpec.segmentGranularity while old segments remain.

Related errors


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