{"id":"380f2f3f11a4196d","repo":"go-redis/redis","slug":"redis-excludeempty-is-not-allowed-with-groupby","errorCode":null,"errorMessage":"redis: EXCLUDEEMPTY is not allowed with GROUPBY","messagePattern":"redis: EXCLUDEEMPTY is not allowed with GROUPBY","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"timeseries_commands.go","lineNumber":172,"sourceCode":"\tcase VarP:\n\t\treturn \"VAR.P\"\n\tcase VarS:\n\t\treturn \"VAR.S\"\n\tcase Twa:\n\t\treturn \"TWA\"\n\tcase CountNaN:\n\t\treturn \"COUNTNAN\"\n\tcase CountAll:\n\t\treturn \"COUNTALL\"\n\tdefault:\n\t\treturn \"\"\n\t}\n}\n\nvar (\n\terrTSMultiAggregationGroupBy = errors.New(\"redis: GROUPBY is not allowed when multiple aggregators are specified\")\n\terrTSAggregationConflict     = errors.New(\"redis: setting both Aggregator and Aggregators is not allowed; use Aggregators instead because Aggregator is deprecated\")\n\terrTSExcludeEmptyGroupBy     = errors.New(\"redis: EXCLUDEEMPTY is not allowed with GROUPBY\")\n)\n\nfunc formatAggregationArgs(aggregator Aggregator, aggregators []Aggregator) (string, int, error) {\n\tif aggregator != Invalid && len(aggregators) > 0 {\n\t\treturn \"\", 0, errTSAggregationConflict\n\t}\n\tif len(aggregators) == 0 {\n\t\tif aggregator == Invalid {\n\t\t\treturn \"\", 0, nil\n\t\t}\n\t\taggregationArg, err := formatAggregatorArg(aggregator)\n\t\tif err != nil {\n\t\t\treturn \"\", 0, err\n\t\t}\n\t\treturn aggregationArg, 1, nil\n\t}\n\n\tparts := make([]string, len(aggregators))","sourceCodeStart":154,"sourceCodeEnd":190,"githubUrl":"https://github.com/go-redis/redis/blob/36d97525cd8076aed67cddf54778e9ea84550929/timeseries_commands.go#L154-L190","documentation":"Returned (set on the cmd) by TSMRangeWithArgs/TSMRevRangeWithArgs when ExcludeEmpty is true together with GroupByLabel or Reducer. Redis does not allow EXCLUDEEMPTY alongside GROUPBY/REDUCE in TS.MRANGE; go-redis enforces this client-side. The check is options.ExcludeEmpty && (options.GroupByLabel != nil || options.Reducer != nil).","triggerScenarios":"Setting TSMRangeOptions.ExcludeEmpty = true while also setting GroupByLabel or Reducer. Combining empty-series filtering with label-based grouping.","commonSituations":"Config-driven query builders that enable all options by default. Dashboards that want both noise reduction (exclude empty) and grouping, not realizing Redis forbids the combination.","solutions":["Disable ExcludeEmpty when using GroupByLabel or Reducer.","If excluding empty series is essential, drop the grouping/reducer and filter empties client-side after the query.","Validate the options combination before calling and surface a clear error to the caller."],"exampleFix":"// before — incompatible options\nopts := &redis.TSMRangeOptions{\n    ExcludeEmpty: true,\n    GroupByLabel: \"host\",\n}\nclient.TSMRangeWithArgs(ctx, from, to, filters, opts)\n\n// after — pick one\nopts := &redis.TSMRangeOptions{\n    GroupByLabel: \"host\",\n    // ExcludeEmpty omitted (false)\n}","handlingStrategy":"validation","validationCode":"func validateExcludeEmpty(o *redis.TSMRangeOptions) error {\n    if o.ExcludeEmpty && (o.GroupByLabel != nil || o.Reducer != nil) {\n        return errors.New(\"ExcludeEmpty cannot be used with GroupByLabel/Reducer\")\n    }\n    return nil\n}","typeGuard":null,"tryCatchPattern":"cmd := c.TSMRangeWithArgs(ctx, from, to, filters, opts)\nif err := cmd.Err(); err != nil {\n    if err.Error() == \"redis: EXCLUDEEMPTY is not allowed with GROUPBY\" {\n        // disable ExcludeEmpty or drop grouping\n    }\n}","preventionTips":["Never set ExcludeEmpty together with GroupByLabel/Reducer.","Filter empty series client-side if both behaviors are needed.","Document the mutually-exclusive options in your query layer."],"tags":["timeseries","validation","aggregation","api-misuse","client-side"],"analyzedSha":"36d97525cd8076aed67cddf54778e9ea84550929","analyzedAt":"2026-08-06T01:08:27.376Z","schemaVersion":2}