redis/go-redis · error
redis.Scan(non-pointer %T)
Error message
redis.Scan(non-pointer %T)
What it means
hscan.Struct (exposed as redis.Struct, used by HGETALL-based struct scanning) requires the destination to be a non-nil pointer to a struct. If dst is not a pointer or is a nil pointer, Struct returns 'redis.Scan(non-pointer %T)'. This is a caller-side type misuse detected via reflection before any Redis data is touched.
Source
Thrown at internal/hscan/hscan.go:60
reflect.Ptr: decodeUnsupported,
reflect.Slice: decodeSlice,
reflect.String: decodeString,
reflect.Struct: decodeUnsupported,
reflect.UnsafePointer: decodeUnsupported,
}
// 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")View on GitHub (pinned to c5cad058c7)
Solutions
- Pass a pointer to a struct: redis.Scan(&user)
- Ensure the pointer is non-nil and initialized
- Verify the pointed-to type is a struct, not a map/slice
- When dst is interface{}, assert it holds a *T before calling Scan
Example fix
// before var user User res, err := redis.Scan(user) // redis.Scan(non-pointer hscan.User) // after var user User res, err := redis.Scan(&user)
Defensive patterns
Strategy: validation
Validate before calling
func validScanDst(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 {
if strings.Contains(err.Error(), "non-pointer") {
return fmt.Errorf("Scan requires &struct: %w", err)
}
} Prevention
- Always pass &myStruct to redis.Scan
- Check interfaces holding destinations for pointer semantics
- Prefer typed function parameters (*User) over interface{} for scan helpers
When it happens
Trigger: redis.Scan(myStruct) instead of redis.Scan(&myStruct); passing a nil typed pointer (*MyStruct)(nil); passing a map or slice address where a struct pointer is required.
Common situations: Copying examples and forgetting the &; storing the destination in an interface{} that holds a non-pointer; scanning into a map[string]string instead of a struct.
Related errors
- redis.Scan(non-struct %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/d5340911a8492d2f.
Report an issue: GitHub.