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 err

View on GitHub (pinned to c5cad058c7)

Solutions

  1. Change the destination to a struct whose fields map to the hash fields
  2. Use r.MapScan(ctx, val) if you want a map result instead
  3. 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

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


AI-assisted analysis of redis/go-redis@c5cad058c7 (2026-09-01). Data as JSON: /api/errors/40ffb36dc04f45c7. Report an issue: GitHub.