go-redis/redis · error
redis: invalid timeseries aggregator at index %d[%d]: Invali
Error message
redis: invalid timeseries aggregator at index %d[%d]: Invalid (%d)
What it means
Returned by buildNRangeAggregationArgs when an element inside a per-key aggregator spec equals the Invalid constant (0). The message reports both the outer spec index i and the inner position [j], plus the Invalid value, to pinpoint the offending entry.
Source
Thrown at timeseries_commands.go:1387
}
// buildNRangeAggregationArgs validates and returns one aggregator spec string per key for
// TS.NRANGE / TS.NREVRANGE. The number of specs must equal the number of keys. Each spec
// lists one or more aggregators for its key and is emitted as a single comma-joined wire
// token; specs for different keys are separate wire tokens.
func buildNRangeAggregationArgs(keys []string, aggregators [][]Aggregator) ([]string, error) {
if len(aggregators) != len(keys) {
return nil, fmt.Errorf("redis: TS.NRANGE/TS.NREVRANGE requires exactly %d aggregator spec(s), got %d", len(keys), len(aggregators))
}
parts := make([]string, len(aggregators))
for i, spec := range aggregators {
if len(spec) == 0 {
return nil, fmt.Errorf("redis: empty timeseries aggregator spec at index %d", i)
}
names := make([]string, len(spec))
for j, agg := range spec {
if agg == Invalid {
return nil, fmt.Errorf("redis: invalid timeseries aggregator at index %d[%d]: Invalid (%d)", i, j, agg)
}
s := agg.String()
if s == "" {
return nil, fmt.Errorf("redis: invalid timeseries aggregator at index %d[%d]: %d", i, j, agg)
}
names[j] = s
}
parts[i] = strings.Join(names, ",")
}
return parts, nil
}
// appendNRangeOptions appends optional TS.NRANGE / TS.NREVRANGE arguments to args.
func appendNRangeOptions(
args []interface{},
keys []string,
latest bool,
filterByTS []int,View on GitHub (pinned to 36d97525cd)
Solutions
- Replace or remove any redis.Invalid entry inside each spec.
- Filter inner slices before the call: spec = slices.DeleteFunc(spec, func(a redis.Aggregator) bool { return a == redis.Invalid }).
- Use append to build inner specs so only explicitly-set values are included.
Example fix
// before
opts := &redis.TSNRangeOptions{
Aggregators: [][]redis.Aggregator{{redis.Avg, redis.Invalid}},
}
// after
opts := &redis.TSNRangeOptions{
Aggregators: [][]redis.Aggregator{{redis.Avg, redis.Sum}},
} Defensive patterns
Strategy: validation
Validate before calling
func validateNRangeSpecs(aggs [][]redis.Aggregator) error {
for i, spec := range aggs {
for j, a := range spec {
if a == redis.Invalid {
return fmt.Errorf("Invalid aggregator at [%d][%d]", i, j)
}
}
}
return nil
} Type guard
func isValidAggregator(a redis.Aggregator) bool { return a != redis.Invalid && a <= redis.CountAll } Prevention
- Populate inner specs fully with append, not make with partial fill.
- Filter redis.Invalid out of each inner spec before the call.
- Use named constants for every aggregator assignment.
When it happens
Trigger: Passing Aggregators where some inner []Aggregator contains redis.Invalid or a zero-value element, e.g. [][]Aggregator{{redis.Invalid}}.
Common situations: Allocating an inner slice with make([]redis.Aggregator, k) and only partially filling it, or merging specs from a source that uses 0 as a no-op.
Related errors
- redis: invalid timeseries aggregator at index %d: Invalid (%
- redis: TS.NRANGE/TS.NREVRANGE requires exactly %d aggregator
- redis: empty timeseries aggregator spec at index %d
- redis: invalid timeseries aggregator at index %d[%d]: %d
- redis: invalid timeseries aggregator at index %d: %d
AI-assisted analysis of go-redis/redis@36d97525cd (2026-08-06).
Data as JSON: /data/errors/85f26cc7ff58a146.json.
Report an issue: GitHub.