apache/druid · error · ISE
Failed to get shardSpec for interval
Error message
Failed to get shardSpec for interval[%s]
What it means
ShardSpecs maintains a map of intervals to lists of BucketNumberedShardSpec produced during determineShardSpecs. getShardSpec looks up the shard specs for the row's interval and throws ISE when no shard specs were computed for that interval, meaning the row's timestamp bucket was never part of the shard-spec planning phase.
Solutions
- Check the offending row's timestamp and the task's granularitySpec intervals; ensure rows fall within configured intervals or enable dropRowOnOutOfInterval / widen the intervals.
- Re-run shard-spec determination (determineShardSpecs) before reading rows so the map is fully populated.
- Verify queryGranularity matches the data — rows bucketed to a granularity not covered by the shard specs plan will have no entry.
- Filter or route out-of-range rows before indexing instead of letting them reach getShardSpec.
Example fix
// before
BucketNumberedShardSpec<?> spec = shardSpecs.getShardSpec(interval, row); // ISE if interval unplanned
// after
if (!shardSpecs.hasShardSpec(interval)) {
log.warn("Dropping row outside planned intervals: %s", row);
return null;
}
BucketNumberedShardSpec<?> spec = shardSpecs.getShardSpec(interval, row); Defensive patterns
Strategy: validation
Validate before calling
if (rows.stream().map(r -> gran.bucketStart(r.getTimestamp())).anyMatch(t -> !plannedIntervals.contains(new Interval(t, gran)))) {
throw new IllegalArgumentException("Rows exist outside planned shard-spec intervals");
} Type guard
boolean isPlanned(ShardSpecs specs, Interval interval) { return specs != null && specs.getShardSpecsForInterval(interval) != null && !specs.getShardSpecsForInterval(interval).isEmpty(); } Try / catch
try {
return shardSpecs.getShardSpec(interval, row);
} catch (IllegalStateException e) {
if (e.getMessage().startsWith("Failed to get shardSpec")) {
log.debug("Row outside planned intervals, dropping: %s", row.getId());
return null;
}
throw e;
} Prevention
- Ensure input timestamps fall within the task's granularitySpec intervals
- Enable dropping of out-of-interval rows before the shard-spec phase
- Keep queryGranularity consistent between shard-spec determination and row processing
- Run determineShardSpecs before any per-row getShardSpec calls
When it happens
Trigger: Calling getShardSpec(interval, row) with an interval that is absent from the map — typically because the input row's timestamp, truncated to queryGranularity, falls into an interval for which no shard specs were determined (e.g. rows outside the configured granularity/intervals of the task), or getShardSpec is invoked before determineShardSpecs populated the map.
Common situations: Ingesting rows whose timestamps fall outside the task's configured intervals (late-arriving or mistimed data with fixOffsetsTimestampGranularity disabled); custom tasks calling getShardSpec against a partially built ShardSpecs map; clock-skewed producers emitting timestamps in unexpected buckets.
Understand the failure class
Background: 'Could not be found', 'does not exist', 'not found in database': the resource-not-found family when an ID, slug, key, or URI lookup comes back empty — this error's family across 20 libraries.
Related errors
- Could not find interval for timestamp
- interval[ ] does not encapsulate the full range of…
- A-Not-B requires at least 1 sketch
- Access-Check-Result
- Action [ ] failed for worker [ ] with status ( )
AI-assisted analysis of apache/druid@9b90983fd2 (2026-09-07).
Data as JSON: /api/errors/bc3cad96fe8b7177.
Report an issue: GitHub.
Appendix: source
Thrown at indexing-service/src/main/java/org/apache/druid/indexing/common/task/ShardSpecs.java:57
ShardSpecs(final Map<Interval, List<BucketNumberedShardSpec<?>>> map, Granularity queryGranularity)
{
this.map = map;
this.queryGranularity = queryGranularity;
}
/**
* Return a shardSpec for the given interval and input row.
*
* @param interval interval for shardSpec
* @param row input row
*
* @return a shardSpec
*/
BucketNumberedShardSpec<?> getShardSpec(Interval interval, InputRow row)
{
final List<BucketNumberedShardSpec<?>> shardSpecs = map.get(interval);
if (shardSpecs == null || shardSpecs.isEmpty()) {
throw new ISE("Failed to get shardSpec for interval[%s]", interval);
}
final long truncatedTimestamp = queryGranularity.bucketStart(row.getTimestamp()).getMillis();
return (BucketNumberedShardSpec<?>) shardSpecs.get(0).getLookup(shardSpecs).getShardSpec(truncatedTimestamp, row);
}
}
View on GitHub (pinned to 9b90983fd2)