{"record":{"id":"1cf81a7f2c0e2cc2","repo":"apache/druid","slug":"non-aligned-segments-s-for-granularity-s","errorCode":null,"errorMessage":"Non-aligned segments %s for granularity[%s]","messagePattern":"Non-aligned segments (.+?) for granularity\\[(.+?)\\]","errorType":"exception","errorClass":"ISE","httpStatus":null,"severity":"error","filePath":"indexing-service/src/main/java/org/apache/druid/indexing/common/task/TaskLockHelper.java","lineNumber":170,"sourceCode":"    final Granularity granularityFromSegments = AbstractBatchIndexTask.findGranularityFromSegments(segments);\n    if (granularityFromSegments != null) {\n      if (knownSegmentGranularity == null) {\n        knownSegmentGranularity = granularityFromSegments;\n      } else {\n        if (!knownSegmentGranularity.equals(granularityFromSegments)) {\n          throw new ISE(\n              \"Found a different granularity from knownSegmentGranularity[%s] in segments[%s]\",\n              knownSegmentGranularity,\n              segments\n          );\n        }\n        final List<DataSegment> nonAlignedSegments = segments\n            .stream()\n            .filter(segment -> !knownSegmentGranularity.isAligned(segment.getInterval()))\n            .collect(Collectors.toList());\n\n        if (!nonAlignedSegments.isEmpty()) {\n          throw new ISE(\n              \"Non-aligned segments %s for granularity[%s]\",\n              SegmentUtils.commaSeparatedIdentifiers(nonAlignedSegments),\n              knownSegmentGranularity\n          );\n        }\n      }\n    } else {\n      throw new ISE(\n          \"Found different granularities in segments %s\",\n          SegmentUtils.commaSeparatedIdentifiers(segments)\n      );\n    }\n  }\n\n  private boolean tryLockSegments(TaskActionClient actionClient, List<DataSegment> segments) throws IOException\n  {\n    final Map<Interval, List<DataSegment>> intervalToSegments = SegmentUtils.groupSegmentsByInterval(segments);\n    for (Entry<Interval, List<DataSegment>> entry : intervalToSegments.entrySet()) {","sourceCodeStart":152,"sourceCodeEnd":188,"githubUrl":"https://github.com/apache/druid/blob/9b90983fd291f26935af934383ce360473179e4d/indexing-service/src/main/java/org/apache/druid/indexing/common/task/TaskLockHelper.java#L152-L188","documentation":"After confirming a single knownSegmentGranularity, verifySegmentGranularity checks that every segment's interval is actually aligned to that granularity (interval start/end on bucket boundaries). Segments whose intervals don't align to the granularity (e.g. custom, non-uniform intervals) cannot be safely locked and replaced, so Druid throws ISE listing the offending segment identifiers.","triggerScenarios":"verifyAndLockExistingSegments encounters segments whose getInterval() is not bucket-aligned to knownSegmentGranularity — e.g. segments created with irregular/unaligned intervals (custom shardSpecs, partial-range compaction artifacts, or hand-crafted segments) while the task uses a regular granularity like hour/day.","commonSituations":"Datasources polluted by segments produced with non-aligned intervals from custom granularity specs or older ingestion runs; compaction with mismatched segmentGranularity; manually adjusted segment metadata.","solutions":["Re-ingest or compact the offending segments so their intervals align to the intended granularity.","Choose a segmentGranularity in the task that matches the actual alignment of the existing segments.","Delete/kill the misaligned unused segments (they may be historical leftovers) and re-run the task."],"exampleFix":"// before\n// task granularity \"hour\" against segments with 37-minute custom intervals -> ISE\n\"segmentGranularity\": \"hour\"\n// after\n\"segmentGranularity\": {\"type\": \"period\", \"period\": \"PT37M\"} // or realign segments via compaction","handlingStrategy":"validation","validationCode":"List<DataSegment> misaligned = segments.stream()\n    .filter(s -> !granularity.isAligned(s.getInterval()))\n    .collect(Collectors.toList());\nif (!misaligned.isEmpty()) {\n  throw new IllegalArgumentException(\"Unaligned segments: \" + misaligned);\n}","typeGuard":"boolean isAligned(DataSegment s, Granularity g) { return g.isAligned(s.getInterval()); }","tryCatchPattern":"try {\n  lockHelper.verifyAndLockExistingSegments(task, interval, segments);\n} catch (IllegalStateException e) {\n  if (e.getMessage().startsWith(\"Non-aligned segments\")) {\n    log.error(\"Realign or kill misaligned segments before replacing\", e);\n  } else { throw e; }\n}","preventionTips":["Avoid custom/non-uniform segment intervals unless necessary","Verify segment interval alignment with Granularity.isAligned before replace tasks","Compact historical misaligned segments to standard granularities","Audit segment metadata after custom shardSpec or interval overrides"],"tags":["druid","segment-granularity","alignment","locking"],"backgroundTag":"invalid-argument-value","analyzedSha":"9b90983fd291f26935af934383ce360473179e4d","analyzedAt":"2026-09-07T13:32:30.957Z","contentChangedAt":"2026-09-07T13:32:30.957Z","schemaVersion":2},"datasetVersion":"2026-09-17T15:17:12.973Z"}