{"id":"09808a3faa3d1ef6","repo":"redis/redis-py","slug":"groupby-is-not-allowed-when-multiple-aggregators-a","errorCode":null,"errorMessage":"GROUPBY is not allowed when multiple aggregators are specified","messagePattern":"GROUPBY is not allowed when multiple aggregators are specified","errorType":"validation","errorClass":"DataError","httpStatus":null,"severity":"error","filePath":"redis/commands/timeseries/commands.py","lineNumber":1420,"sourceCode":"        filter_by_ts: List[int] | None,\n        filter_by_min_value: int | None,\n        filter_by_max_value: int | None,\n        groupby: str | None,\n        reduce: str | None,\n        select_labels: List[str] | None,\n        align: int | str | None,\n        latest: bool | None,\n        bucket_timestamp: str | None,\n        empty: bool | None,\n        exclude_empty: bool | None,\n    ):\n        \"\"\"Create TS.MRANGE and TS.MREVRANGE arguments.\"\"\"\n        if (\n            groupby is not None\n            and isinstance(aggregation_type, list)\n            and len(aggregation_type) > 1\n        ):\n            raise DataError(\n                \"GROUPBY is not allowed when multiple aggregators are specified\"\n            )\n        if exclude_empty and groupby is not None:\n            raise DataError(\"EXCLUDEEMPTY is not allowed with GROUPBY\")\n        params: list[EncodableT] = [from_time, to_time]\n        self._append_latest(params, latest)\n        self._append_filer_by_ts(params, filter_by_ts)\n        self._append_filer_by_value(params, filter_by_min_value, filter_by_max_value)\n        self._append_with_labels(params, with_labels, select_labels)\n        self._append_count(params, count)\n        self._append_align(params, align)\n        self._append_aggregation(params, aggregation_type, bucket_size_msec)\n        self._append_bucket_timestamp(params, bucket_timestamp)\n        self._append_empty(params, empty)\n        self._append_exclude_empty(params, exclude_empty)\n        params.extend([\"FILTER\"])\n        params += filters\n        self._append_groupby_reduce(params, groupby, reduce)","sourceCodeStart":1402,"sourceCodeEnd":1438,"githubUrl":"https://github.com/redis/redis-py/blob/da03cdc7e8731092b13e395605c3c1fb2de25de1/redis/commands/timeseries/commands.py#L1402-L1438","documentation":"Raised by the TS.MRANGE/TS.MREVRANGE parameter builder when groupby is set AND aggregation_type is a list with more than one aggregator. The server cannot apply GROUPBY REDUCE across multiple aggregators, so the combination is invalid. Use a single aggregator with GROUPBY, or drop GROUPBY when you need multiple aggregators.","triggerScenarios":"client.ts().mrange('-', '+', filters=['region=us'], aggregation_type=['avg','sum'], groupby='region', reduce='sum'). The check fires before the command is sent.","commonSituations":"Enabling multi-aggregator support (Redis 8.8+) while keeping an existing GROUPBY/REDUCE pipeline; copy-pasting a config that combined both; treating aggregation_type as always-list.","solutions":["Use a single aggregator when you need GROUPBY: aggregation_type='avg', groupby='region', reduce='sum'.","Drop groupby/reduce to use multiple aggregators: aggregation_type=['avg','sum'] with groupby=None.","Run two separate mrange calls if you need both grouping and multiple aggregations."],"exampleFix":"// before\nclient.ts().mrange('-', '+', filters=f, aggregation_type=['avg','sum'], groupby='region', reduce='sum')\n// after\nclient.ts().mrange('-', '+', filters=f, aggregation_type='avg', groupby='region', reduce='sum')","handlingStrategy":"validation","validationCode":"def validate_mrange_agg(agg_type, groupby):\n    if groupby is not None and isinstance(agg_type, list) and len(agg_type) > 1:\n        raise ValueError(\"Use a single aggregator with GROUPBY, or drop GROUPBY for multi-agg.\")\n    return agg_type","typeGuard":"def is_groupby_compatible(agg_type, groupby) -> bool:\n    if groupby is None:\n        return True\n    if isinstance(agg_type, list) and len(agg_type) > 1:\n        return False\n    return True","tryCatchPattern":"try:\n    client.ts().mrange('-', '+', filters=f, aggregation_type=agg, groupby=g, reduce=r)\nexcept Exception as e:\n    if 'GROUPBY' in str(e):\n        agg = agg[0] if isinstance(agg, list) else agg\n        client.ts().mrange('-', '+', filters=f, aggregation_type=agg, groupby=g, reduce=r)\n    else:\n        raise","preventionTips":["Keep GROUPBY paired with a single (string) aggregator.","Only use aggregator lists when groupby is None.","Document the mutual exclusion in your query helpers."],"tags":["redistimeseries","timeseries","mrange","aggregation","groupby","argument-error"],"analyzedSha":"da03cdc7e8731092b13e395605c3c1fb2de25de1","analyzedAt":"2026-08-04T20:26:47.563Z","schemaVersion":2}