go-redis/redis · error

redis: EXCLUDEEMPTY is not allowed with GROUPBY

Error message

redis: EXCLUDEEMPTY is not allowed with GROUPBY

What it means

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).

Source

Thrown at timeseries_commands.go:172

	case VarP:
		return "VAR.P"
	case VarS:
		return "VAR.S"
	case Twa:
		return "TWA"
	case CountNaN:
		return "COUNTNAN"
	case CountAll:
		return "COUNTALL"
	default:
		return ""
	}
}

var (
	errTSMultiAggregationGroupBy = errors.New("redis: GROUPBY is not allowed when multiple aggregators are specified")
	errTSAggregationConflict     = errors.New("redis: setting both Aggregator and Aggregators is not allowed; use Aggregators instead because Aggregator is deprecated")
	errTSExcludeEmptyGroupBy     = errors.New("redis: EXCLUDEEMPTY is not allowed with GROUPBY")
)

func formatAggregationArgs(aggregator Aggregator, aggregators []Aggregator) (string, int, error) {
	if aggregator != Invalid && len(aggregators) > 0 {
		return "", 0, errTSAggregationConflict
	}
	if len(aggregators) == 0 {
		if aggregator == Invalid {
			return "", 0, nil
		}
		aggregationArg, err := formatAggregatorArg(aggregator)
		if err != nil {
			return "", 0, err
		}
		return aggregationArg, 1, nil
	}

	parts := make([]string, len(aggregators))

View on GitHub (pinned to 36d97525cd)

Solutions

  1. Disable ExcludeEmpty when using GroupByLabel or Reducer.
  2. If excluding empty series is essential, drop the grouping/reducer and filter empties client-side after the query.
  3. Validate the options combination before calling and surface a clear error to the caller.

Example fix

// before — incompatible options
opts := &redis.TSMRangeOptions{
    ExcludeEmpty: true,
    GroupByLabel: "host",
}
client.TSMRangeWithArgs(ctx, from, to, filters, opts)

// after — pick one
opts := &redis.TSMRangeOptions{
    GroupByLabel: "host",
    // ExcludeEmpty omitted (false)
}
Defensive patterns

Strategy: validation

Validate before calling

func validateExcludeEmpty(o *redis.TSMRangeOptions) error {
    if o.ExcludeEmpty && (o.GroupByLabel != nil || o.Reducer != nil) {
        return errors.New("ExcludeEmpty cannot be used with GroupByLabel/Reducer")
    }
    return nil
}

Try / catch

cmd := c.TSMRangeWithArgs(ctx, from, to, filters, opts)
if err := cmd.Err(); err != nil {
    if err.Error() == "redis: EXCLUDEEMPTY is not allowed with GROUPBY" {
        // disable ExcludeEmpty or drop grouping
    }
}

Prevention

When it happens

Trigger: Setting TSMRangeOptions.ExcludeEmpty = true while also setting GroupByLabel or Reducer. Combining empty-series filtering with label-based grouping.

Common situations: 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.

Related errors


AI-assisted analysis of go-redis/redis@36d97525cd (2026-08-06). Data as JSON: /data/errors/380f2f3f11a4196d.json. Report an issue: GitHub.