apache/druid · error · IllegalArgumentException

Granularity is not supported. [%s]

Error message

Granularity is not supported. [%s]

What it means

GranularityType.fromPeriod() converts a Joda Period into a GranularityType enum only when the period has exactly one non-zero component (e.g. PT1H or P1D). While scanning the period's field values it throws this IAE if it finds a second non-zero field, because a compound period like 'P1DT2H' does not map to any single granularity bucket.

Source

Thrown at processing/src/main/java/org/apache/druid/java/util/common/granularity/GranularityType.java:201

      }
    }
    return false;
  }

  /**
   * Note: This is only an estimate based on the values in period.
   * This will not work for complicated periods that represent say 1 year 1 day
   */
  public static GranularityType fromPeriod(Period period)
  {
    int[] vals = period.getValues();
    int index = -1;
    for (int i = 0; i < vals.length; i++) {
      if (vals[i] != 0) {
        if (index < 0) {
          index = i;
        } else {
          throw new IAE("Granularity is not supported. [%s]", period);
        }
      }
    }

    switch (index) {
      case 0:
        return GranularityType.YEAR;
      case 1:
        if (vals[index] == 3) {
          return GranularityType.QUARTER;
        } else if (vals[index] == 1) {
          return GranularityType.MONTH;
        }
        break;
      case 2:
        return GranularityType.WEEK;
      case 3:
        return GranularityType.DAY;

View on GitHub (pinned to 9b90983fd2)

Solutions

  1. Use a simple Period with exactly one non-zero field, e.g. Period.parse("PT2H") instead of "PT1H30M"
  2. If a compound bucket is needed, pick the larger unit and set origin/timeZone on PeriodGranularity instead, or use an arbitrary-duration approach
  3. Parse the input period first and validate that at most one of getYears()..getMillis() is non-zero before calling fromPeriod

Example fix

// before
Granularity gran = GranularityType.fromPeriod(Period.parse("P1DT2H"));
// after
Granularity gran = GranularityType.fromPeriod(Period.parse("P1D")); // single non-zero field
Defensive patterns

Strategy: validation

Validate before calling

static boolean isSimplePeriod(Period p) {
  int nz = 0;
  int[] f = {p.getYears(), p.getMonths(), p.getWeeks(), p.getDays(), p.getHours(), p.getMinutes(), p.getSeconds(), p.getMillis()};
  for (int v : f) { if (v != 0) nz++; }
  return nz == 1;
}
// call: if (!isSimplePeriod(period)) throw new IllegalArgumentException(...);

Type guard

if (GranularityType.fromPeriod(period) == null || !isSimplePeriod(period)) { /* fallback */ }

Try / catch

try { t = GranularityType.fromPeriod(period); } catch (IllegalArgumentException e) { /* fall back to PeriodGranularity or reject config */ }

Prevention

When it happens

Trigger: Calling GranularityType.fromPeriod(new Period("P1DT2H")) or any Period with two or more non-zero fields (weeks+days, hours+minutes, etc.). Also thrown when the period's fields don't align with the enum's supported magnitudes (e.g. PT90M after the switch falls through).

Common situations: Users supply compound query granularities like 'P1W2D' or 'PT1H30M' in JSON query specs or ingestion granularity configs; misconfigured period strings from external systems that normalize durations into compound periods.

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


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