apache/druid · error · BadQueryContextException

Expected key [%s] to be a Granularity, but got [%s]

Error message

Expected key [%s] to be a Granularity, but got [%s]

What it means

QueryContext.getGranularity parses a query context key into a Granularity (e.g. 'all', 'day', or a period string) using the object mapper. When the string cannot be deserialized to a Granularity, it throws QueryContexts.badTypeException declaring the key must be 'a Granularity'. The query fails during context validation.

Source

Thrown at processing/src/main/java/org/apache/druid/query/QueryContext.java:251

  }

  public <E extends Enum<E>> E getEnum(String key, Class<E> clazz, E defaultValue)
  {
    return QueryContexts.getAsEnum(key, get(key), clazz, defaultValue);
  }

  public Granularity getGranularity(String key, ObjectMapper jsonMapper)
  {
    final String granularityString = getString(key);
    if (granularityString == null) {
      return null;
    }

    try {
      return jsonMapper.readValue(granularityString, Granularity.class);
    }
    catch (IOException e) {
      throw QueryContexts.badTypeException(key, "a Granularity", granularityString);
    }
  }

  public boolean isDebug()
  {
    return getBoolean(QueryContexts.ENABLE_DEBUG, QueryContexts.DEFAULT_ENABLE_DEBUG);
  }

  public boolean isBySegment()
  {
    return isBySegment(QueryContexts.DEFAULT_BY_SEGMENT);
  }

  public boolean isBySegment(boolean defaultValue)
  {
    return getBoolean(QueryContexts.BY_SEGMENT_KEY, defaultValue);
  }

View on GitHub (pinned to 9b90983fd2)

Solutions

  1. Use a valid simple granularity string: 'second', 'minute', 'fifteen_minute', 'hour', 'day', 'week', 'month', 'quarter', 'year', or 'all'.
  2. For custom periods, pass a valid JSON duration granularity: {"type":"period","period":"P1D"}.
  3. Check the error message: it includes the offending value; fix the exact string you passed.

Example fix

// before
queryContext.put("timestampResultFieldGranularity", "daily");
// after
queryContext.put("timestampResultFieldGranularity", "day");
Defensive patterns

Strategy: validation

Validate before calling

Set<String> valid = Set.of("second","minute","fifteen_minute","thirty_minute","hour","day","week","month","quarter","year","all");
String g = (String) queryContext.get("timestampResultFieldGranularity");
if (g != null && !valid.contains(g.trim().toLowerCase()) && !g.trim().startsWith("{")) {
  throw new IllegalArgumentException("Not a Granularity: " + g);
}

Prevention

When it happens

Trigger: Setting a granularity-typed context key (e.g. timestampResultFieldGranularity) to a value like 'daily', 'dayly', or '1 day' that Jackson cannot map to Granularity; called from timestampResultFieldGranularity.

Common situations: Users confuse Granularity names with SQL interval syntax ('day' is valid, 'daily' and '7 days' are not), or pass a JSON object where a string like '{"type":"period","period":"P1D"}' with wrong fields is given.

Understand the failure class

Background: "Invalid value" and "allowed values are" config errors: what your library rejected and how to fix it — this error's family across 41 libraries.

Related errors


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