go-redis/redis · error

redis: invalid timeseries aggregator: %d

Error message

redis: invalid timeseries aggregator: %d

What it means

Returned by formatAggregatorArg when aggregator.String() returns the empty string, which occurs for any Aggregator value not covered by the switch (i.e. the Invalid zero value or an out-of-range cast). This is the single-aggregator code path in formatAggregationArgs and the shared helper.

Source

Thrown at timeseries_commands.go:208

	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
	FilterByValue []int
	Count         int
	Align         interface{}
	// Deprecated: use Aggregators instead.
	Aggregator      Aggregator
	Aggregators     []Aggregator
	BucketDuration  int
	BucketTimestamp interface{}
	Empty           bool
}

View on GitHub (pinned to 36d97525cd)

Solutions

  1. Set the Aggregator field to a valid named constant (redis.Avg, redis.Sum, etc.).
  2. Prefer the Aggregators slice over the deprecated single Aggregator field.
  3. Bounds-check any cast aggregator against [redis.Avg, redis.CountAll] before use.

Example fix

// before
opts := &redis.TSRangeOptions{Aggregator: redis.Aggregator(0)} // Invalid
client.TSRangeWithArgs(ctx, key, 0, -1, opts)

// after
opts := &redis.TSRangeOptions{Aggregators: []redis.Aggregator{redis.Avg}}
client.TSRangeWithArgs(ctx, key, 0, -1, opts)
Defensive patterns

Strategy: validation

Validate before calling

func validSingleAggregator(a redis.Aggregator) error {
    if a == redis.Invalid || a > redis.CountAll {
        return fmt.Errorf("aggregator %d is not valid", a)
    }
    return nil
}

Type guard

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

Prevention

When it happens

Trigger: Passing a single Aggregator (the deprecated Aggregator field) that is either redis.Invalid or an out-of-range cast value such as redis.Aggregator(50).

Common situations: Default zero-value Aggregator left in TSOptions/TSRangeOptions when the caller intended to set one, or an integer cast from external data without validation.

Related errors


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