go-redis/redis · error
args should have the same number of keys and vals
Error message
args should have the same number of keys and vals
What it means
internal/hscan.Scan returns this when the keys and vals slices passed to it have different lengths (hscan.go:77-78). HSCAN/MGET-style key/value pairs must be balanced; a mismatch implies a malformed result set or a caller bug. The error surfaces to users via the exported redis.Scan / ScanStruct helpers.
Source
Thrown at internal/hscan/hscan.go:78
return StructValue{}, fmt.Errorf("redis.Scan(non-pointer %T)", dst)
}
v = v.Elem()
if v.Kind() != reflect.Struct {
return StructValue{}, fmt.Errorf("redis.Scan(non-struct %T)", dst)
}
return StructValue{
spec: globalStructMap.get(v.Type()),
value: v,
}, nil
}
// Scan scans the results from a key-value Redis map result set to a destination struct.
// The Redis keys are matched to the struct's field with the `redis` tag.
func Scan(dst interface{}, keys []interface{}, vals []interface{}) error {
if len(keys) != len(vals) {
return errors.New("args should have the same number of keys and vals")
}
strct, err := Struct(dst)
if err != nil {
return err
}
// Iterate through the (key, value) sequence.
for i := 0; i < len(vals); i++ {
key, ok := keys[i].(string)
if !ok {
continue
}
val, ok := vals[i].(string)
if !ok {
continue
}View on GitHub (pinned to 36d97525cd)
Solutions
- Ensure len(keys) == len(vals) before calling Scan.
- Build keys/vals from the alternating HSCAN slice with a stride of 2 so they cannot diverge.
- Prefer redis.NewScanCmd / ScanStruct over manual slicing.
Example fix
// before
redis.Scan(&dst, keys[:n], vals) // length mismatch
// after
n := len(res) / 2
keys := make([]interface{}, n)
vals := make([]interface{}, n)
for i := 0; i < n; i++ {
keys[i] = res[i*2]
vals[i] = res[i*2+1]
}
redis.Scan(&dst, keys, vals) Defensive patterns
Strategy: validation
Validate before calling
if len(keys) != len(vals) {
return fmt.Errorf("keys/vals length mismatch: %d vs %d", len(keys), len(vals))
}
return redis.Scan(&dst, keys, vals) Type guard
func balancedKV(keys, vals []interface{}) bool {
return len(keys) == len(vals)
} Try / catch
if err := redis.Scan(&dst, keys, vals); err != nil {
if strings.Contains(err.Error(), "same number of keys and vals") {
// re-derive balanced slices from the alternating result
}
} Prevention
- Derive keys/vals from the alternating HSCAN slice with stride 2.
- Prefer redis.ScanStruct / NewScanCmd over manual slicing.
When it happens
Trigger: Calling redis.Scan(&dst, keys, vals) (or HSCAN-driven ScanStruct) where len(keys) != len(vals) — e.g. truncating one slice, mismatched parallel slices, or a corrupted HSCAN reply.
Common situations: Manually splitting an HSCAN result into keys/vals arrays and getting the slicing wrong, or a custom deserializer feeding unbalanced slices.
Related errors
- GeoRadius does not support Store or StoreDist
- GeoRadiusStore requires Store or StoreDist
- GeoRadiusByMember does not support Store or StoreDist
- GeoRadiusByMemberStore requires Store or StoreDist
- redis: at least one metric must be specified for HOTKEYS STA
AI-assisted analysis of go-redis/redis@36d97525cd (2026-08-06).
Data as JSON: /data/errors/20b98b2e57269048.json.
Report an issue: GitHub.