{"record":{"id":"a912be29fe0b7ebe","repo":"apache/druid","slug":"only-periodgranulaity-is-supported-for-movingavera","errorCode":null,"errorMessage":"Only PeriodGranulaity is supported for movingAverage queries","messagePattern":"Only PeriodGranulaity is supported for movingAverage queries","errorType":"exception","errorClass":"ISE","httpStatus":null,"severity":"error","filePath":"extensions-contrib/moving-average-query/src/main/java/org/apache/druid/query/movingaverage/MovingAverageQueryRunner.java","lineNumber":104,"sourceCode":"    MovingAverageQuery maq = (MovingAverageQuery) query.getQuery();\n    List<Interval> intervals;\n    final Period period;\n\n    // Get the largest bucket from the list of averagers\n    Optional<Integer> opt =\n        maq.getAveragerSpecs().stream().map(AveragerFactory::getNumBuckets).max(Integer::compare);\n    int buckets = opt.orElse(0);\n\n    //Extend the interval beginning by specified bucket - 1\n    if (maq.getGranularity() instanceof PeriodGranularity) {\n      period = ((PeriodGranularity) maq.getGranularity()).getPeriod();\n      int offset = buckets <= 0 ? 0 : (1 - buckets);\n      intervals = maq.getIntervals()\n                     .stream()\n                     .map(i -> new Interval(i.getStart().withPeriodAdded(period, offset), i.getEnd()))\n                     .collect(Collectors.toList());\n    } else {\n      throw new ISE(\"Only PeriodGranulaity is supported for movingAverage queries\");\n    }\n\n    Sequence<Row> resultsSeq;\n    DataSource dataSource = maq.getDataSource();\n    if (maq.getDimensions() != null && !maq.getDimensions().isEmpty() &&\n        (dataSource instanceof TableDataSource || dataSource instanceof UnionDataSource ||\n         dataSource instanceof QueryDataSource)) {\n      // build groupBy query from movingAverage query\n      GroupByQuery.Builder builder = GroupByQuery.builder()\n                                                 .setDataSource(dataSource)\n                                                 .setInterval(intervals)\n                                                 .setDimFilter(maq.getFilter())\n                                                 .setGranularity(maq.getGranularity())\n                                                 .setDimensions(maq.getDimensions())\n                                                 .setAggregatorSpecs(maq.getAggregatorSpecs())\n                                                 .setPostAggregatorSpecs(maq.getPostAggregatorSpecs())\n                                                 .setContext(maq.getContext());\n      GroupByQuery gbq = builder.build();","sourceCodeStart":86,"sourceCodeEnd":122,"githubUrl":"https://github.com/apache/druid/blob/9b90983fd291f26935af934383ce360473179e4d/extensions-contrib/moving-average-query/src/main/java/org/apache/druid/query/movingaverage/MovingAverageQueryRunner.java#L86-L122","documentation":"MovingAverageQueryRunner.run only supports PeriodGranularity for the moving-average bucket computation, since it derives past buckets by applying the period to intervals. Any other granularity (e.g. duration or period-less granularities) reaches the else branch and throws IllegalStateException.","triggerScenarios":"Running a movingAverage/averager query whose 'granularity' is not a PeriodGranularity, e.g. {\"type\": \"duration\", \"duration\": 3600000} or a simple \"day\" string granularity.","commonSituations":"Users familiar with standard group-by queries reusing duration granularities in moving-average queries; SQL-generated or templated queries that always emit duration granularity; misconfigured dashboards.","solutions":["Change the query granularity to a period-based one, e.g. {\"type\": \"period\", \"period\": \"P1D\"}","Use ISO-8601 periods (PT1H, P7D) that match the desired averaging window","If building the query programmatically, construct new PeriodGranularity(new Period(...), null, tz) instead of DurationGranularity"],"exampleFix":"// before\n\"granularity\": {\"type\": \"duration\", \"duration\": 86400000}\n// after\n\"granularity\": {\"type\": \"period\", \"period\": \"P1D\", \"timeZone\": \"UTC\"}","handlingStrategy":"validation","validationCode":"Granularity g = maq.getGranularity();\nif (!(g instanceof PeriodGranularity)) {\n  throw new IllegalArgumentException(\"movingAverage requires period granularity, got: \" + g.getClass().getSimpleName());\n}","typeGuard":"boolean isPeriod(Granularity g) { return g instanceof PeriodGranularity; }","tryCatchPattern":"try { results = runner.run(sequence, responseContext); } catch (IllegalStateException e) { if (e.getMessage().contains(\"PeriodGranulaity\")) { /* rebuild query with period granularity */ } }","preventionTips":["Always use {\"type\":\"period\"} granularity in moving-average queries","Convert duration granularities to ISO-8601 periods when translating queries","Add schema checks in query submission tooling"],"tags":["java","granularity","moving-average-query"],"backgroundTag":"unsupported-operation","analyzedSha":"9b90983fd291f26935af934383ce360473179e4d","analyzedAt":"2026-09-07T13:32:30.957Z","contentChangedAt":"2026-09-07T13:32:30.957Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}