apache/druid · error · IllegalArgumentException
Granularity [%s] is not supported
Error message
Granularity [%s] is not supported
What it means
Thrown by QueryKitUtils.makeSegmentGranularityVirtualColumn when the configured segment granularity is not Granularities.ALL and not a PeriodGranularity. MSQ builds a time-flooring virtual column from a PeriodGranularity; other Granularity implementations (or period granularities with a non-UTC time zone / custom origin) cannot be turned into the bucketing column.
Source
Thrown at multi-stage-query/src/main/java/org/apache/druid/msq/querykit/QueryKitUtils.java:214
*
* @throws IllegalArgumentException if the provided granularity is not supported
*/
@Nullable
public static VirtualColumn makeSegmentGranularityVirtualColumn(
final ObjectMapper jsonMapper,
final QueryContext queryContext
)
{
final Granularity segmentGranularity =
QueryKitUtils.getSegmentGranularityFromContext(jsonMapper, queryContext.asMap());
final String timeColumnName = queryContext.getString(QueryKitUtils.CTX_TIME_COLUMN_NAME);
if (timeColumnName == null || Granularities.ALL.equals(segmentGranularity)) {
return null;
}
if (!(segmentGranularity instanceof PeriodGranularity)) {
throw new IAE("Granularity [%s] is not supported", segmentGranularity);
}
final PeriodGranularity periodSegmentGranularity = (PeriodGranularity) segmentGranularity;
if (periodSegmentGranularity.getOrigin() != null
|| !periodSegmentGranularity.getTimeZone().equals(DateTimeZone.UTC)) {
throw new IAE("Granularity [%s] is not supported", segmentGranularity);
}
return new ExpressionVirtualColumn(
QueryKitUtils.SEGMENT_GRANULARITY_COLUMN,
StringUtils.format(
"timestamp_floor(%s, %s)",
CalciteSqlDialect.DEFAULT.quoteIdentifier(timeColumnName),
Calcites.escapeStringLiteral((periodSegmentGranularity).getPeriod().toString())
),
ColumnType.LONG,
new ExprMacroTable(Collections.singletonList(new TimestampFloorExprMacro()))View on GitHub (pinned to 9b90983fd2)
Solutions
- Use a plain period granularity in UTC with no origin, e.g. {"type":"period","period":"P1D"} (equivalent to "day").
- Use a standard named granularity such as "hour", "day", "month".
- If local-timezone bucketing is needed, precompute the bucket in SQL (e.g. TIME_FLOOR with TIME_SHIFT) instead of relying on segment granularity.
- Remove a custom origin from the period granularity or align data upstream.
Example fix
// before
context.put("segmentGranularity", new DurationGranularity(86400000L, 0L));
// after
context.put("segmentGranularity", new PeriodGranularity(Period.days(1), null, DateTimeZone.UTC)); Defensive patterns
Strategy: validation
Validate before calling
Granularity g = segmentGranularity;
if (g != null && !Granularities.ALL.equals(g) && !(g instanceof PeriodGranularity)) {
throw new IllegalArgumentException("Segment granularity must be a UTC period granularity");
}
if (g instanceof PeriodGranularity) {
PeriodGranularity pg = (PeriodGranularity) g;
if (pg.getOrigin() != null || !pg.getTimeZone().equals(DateTimeZone.UTC)) {
throw new IllegalArgumentException("Period granularity must have null origin and UTC timezone");
}
} Type guard
boolean isSupportedSegmentGranularity(Object g) {
return g == null || Granularities.ALL.equals(g)
|| (g instanceof PeriodGranularity
&& ((PeriodGranularity) g).getOrigin() == null
&& DateTimeZone.UTC.equals(((PeriodGranularity) g).getTimeZone()));
} Try / catch
try {
VirtualColumn vc = QueryKitUtils.makeSegmentGranularityVirtualColumn(timeCol, granularity);
} catch (IllegalArgumentException e) {
granularity = Granularities.DAY; // fall back to a supported period granularity
} Prevention
- Use standard UTC period granularities without origin for segment granularity.
- Avoid DurationGranularity or custom Granularity implementations in MSQ context.
- Handle timezone-specific bucketing in SQL expressions instead.
When it happens
Trigger: Setting the segment granularity context to a granularity type other than PeriodGranularity (e.g. DurationGranularity or a custom implementation), or a PeriodGranularity with an explicit origin or non-UTC timeZone, then generating the __granularity virtual column.
Common situations: Custom granularity objects supplied programmatically; period granularities with timezone offsets for local-time bucketing (unsupported by this path); configs migrated from ingestion specs using duration-based granularities.
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
- Cannot handle dataSource [%s]
- Invalid segment granularity [%s]
- partitionsSpec[%s] is not supported
- %s
- [%s] secondary partition type is not supported
AI-assisted analysis of apache/druid@9b90983fd2 (2026-09-07).
Data as JSON: /api/errors/bac8aef171295cde.
Report an issue: GitHub.