redis/go-redis · error
redis.Scan(non-struct %T)
Error message
redis.Scan(non-struct %T)
What it means
After dereferencing the destination pointer, hscan.Struct checks that the pointed-to value is actually a struct. If dst is a pointer to something else (map, slice, string, number), it returns 'redis.Scan(non-struct %T)'. Struct scanning via HGETALL hash fields only works with struct destinations.
Source
Thrown at internal/hscan/hscan.go:65
}
// Global map of struct field specs that is populated once for every new
// struct type that is scanned. This caches the field types and the corresponding
// decoder functions to avoid iterating through struct fields on subsequent scans.
globalStructMap = newStructMap()
)
func Struct(dst interface{}) (StructValue, error) {
v := reflect.ValueOf(dst)
// The destination to scan into should be a struct pointer.
if v.Kind() != reflect.Ptr || v.IsNil() {
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 errView on GitHub (pinned to c5cad058c7)
Solutions
- Change the destination to a struct whose fields map to the hash fields
- Use r.MapScan(ctx, val) if you want a map result instead
- Add struct tags (redis:"field") to control hash-field mapping
Example fix
// before
m := map[string]string{}
res, err := redis.Scan(&m) // redis.Scan(non-struct map[string]string)
// after
type User struct {
Name string `redis:"name"`
}
u := User{}
res, err := redis.Scan(&u) Defensive patterns
Strategy: validation
Validate before calling
func isStructPtr(dst interface{}) bool {
v := reflect.ValueOf(dst)
return v.Kind() == reflect.Ptr && !v.IsNil() && v.Elem().Kind() == reflect.Struct
} Try / catch
res, err := redis.Scan(dst)
if err != nil && strings.Contains(err.Error(), "non-struct") {
return fmt.Errorf("use MapScan for map destinations: %w", err)
} Prevention
- Only scan into structs; use MapScan for maps
- Document scan-helper signatures as accepting struct pointers
- Add unit tests covering every destination type your helpers accept
When it happens
Trigger: redis.Scan(&myMap), redis.Scan(&mySlice), or redis.Scan(&someString) — a valid non-nil pointer whose element is not a struct kind.
Common situations: Refactoring code from MapScan to StructScan and keeping a map destination; generics/interface{} plumbing that hides the real type; scanning HGETALL into map[string]interface{} via Scan.
Related errors
- redis.Scan(non-pointer %T)
- redis.Scan(unsupported %s)
- cannot scan redis.result %s into struct field %s.%s of type
AI-assisted analysis of redis/go-redis@c5cad058c7 (2026-09-01).
Data as JSON: /api/errors/40ffb36dc04f45c7.
Report an issue: GitHub.