go-redis/redis · error

redis: invalid timeseries aggregator at index %d: %d

Error message

redis: invalid timeseries aggregator at index %d: %d

What it means

Returned by formatAggregationArgs when formatAggregatorArg fails for an element of the Aggregators slice. formatAggregatorArg fails when aggregator.String() returns empty, which happens for any Aggregator value outside the defined iota range (i.e. a value cast from an int greater than CountAll). The message reports the offending index and raw int value.

Source

Thrown at timeseries_commands.go:197

	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))
	for i, agg := range aggregators {
		if agg == Invalid {
			return "", 0, fmt.Errorf("redis: invalid timeseries aggregator at index %d: Invalid (%d)", i, agg)
		}
		aggregationArg, err := formatAggregatorArg(agg)
		if err != nil {
			return "", 0, fmt.Errorf("redis: invalid timeseries aggregator at index %d: %d", i, agg)
		}
		parts[i] = aggregationArg
	}

	return strings.Join(parts, ","), len(parts), nil
}

func formatAggregatorArg(aggregator Aggregator) (string, error) {
	aggregationArg := aggregator.String()
	if aggregationArg == "" {
		return "", fmt.Errorf("redis: invalid timeseries aggregator: %d", aggregator)
	}
	return aggregationArg, nil
}

type TSRangeOptions struct {
	Latest        bool
	FilterByTS    []int

View on GitHub (pinned to 36d97525cd)

Solutions

  1. Validate that each aggregator is within the known range [Avg(1), CountAll(13)] before building the slice.
  2. Reject or clamp out-of-range values when parsing external aggregator indices.
  3. Use the named constants (redis.Avg … redis.CountAll) instead of casting raw ints.

Example fix

// before
agg := redis.Aggregator(getAggregatorIdFromConfig()) // returns 99
opts := &redis.TSRangeOptions{Aggregators: []redis.Aggregator{agg}}

// after
if agg > redis.CountAll || agg <= redis.Invalid {
    return fmt.Errorf("unsupported aggregator id %d", agg)
}
opts := &redis.TSRangeOptions{Aggregators: []redis.Aggregator{agg}}
Defensive patterns

Strategy: validation

Validate before calling

func validAggregators(aggs []redis.Aggregator) error {
    for i, a := range aggs {
        if a < redis.Avg || a > redis.CountAll {
            return fmt.Errorf("aggregator at index %d out of range: %d", i, a)
        }
    }
    return nil
}

Type guard

func isValidAggregator(a redis.Aggregator) bool { return a >= redis.Avg && a <= redis.CountAll }

Prevention

When it happens

Trigger: Passing an Aggregators slice containing a value produced by an illegal cast, e.g. redis.Aggregator(99), or arithmetic that overflows past CountAll (13).

Common situations: Deserialising an aggregator index from an untrusted/config source without bounds-checking, or a typo in a lookup table mapping strings to ints.

Related errors


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