micro/go-micro · error
model: result must be a pointer to a slice
Error message
model: result must be a pointer to a slice
What it means
List unmarshals query results by reflecting into the caller's result parameter, which must be a pointer to a slice (typically *[]*T) so it can be grown and populated. Any other shape — a struct pointer, a map, a nil pointer, or a non-pointer slice — is rejected with this error before any query runs.
Source
Thrown at model/memory.go:147
return err
}
m.mu.Lock()
defer m.mu.Unlock()
tbl := m.tables[schema.Table]
if _, ok := tbl[key]; !ok {
return ErrNotFound
}
delete(tbl, key)
return nil
}
func (m *memoryModel) List(ctx context.Context, result interface{}, opts ...QueryOption) error {
// result must be *[]*T
rv := reflect.ValueOf(result)
if rv.Kind() != reflect.Pointer || rv.Elem().Kind() != reflect.Slice {
return fmt.Errorf("model: result must be a pointer to a slice")
}
sliceVal := rv.Elem()
elemType := sliceVal.Type().Elem() // *T
structType := elemType
if structType.Kind() == reflect.Pointer {
structType = structType.Elem()
}
m.mu.RLock()
s, ok := m.types[structType]
m.mu.RUnlock()
if !ok {
return ErrNotRegistered
}
q := ApplyQueryOptions(opts...)
m.mu.RLock()View on GitHub (pinned to 24529f1404)
Solutions
- Pass a pointer to a slice: declare var users []*User and call List(ctx, &users).
- Ensure the slice's element type matches the model struct (or pointer to it).
- Check that you're not accidentally passing the slice by value — add the & operator.
- Initialize the variable rather than passing a typed nil interface.
Example fix
// before
users := []*User{}
err := store.List(ctx, users) // slice, not pointer
// after
var users []*User
err := store.List(ctx, &users) Defensive patterns
Strategy: type-guard
Validate before calling
// ensure result is *[]*T before calling
func isPtrToSlice(result interface{}) bool {
rv := reflect.ValueOf(result)
return rv.Kind() == reflect.Pointer && rv.Elem().Kind() == reflect.Slice
} Type guard
func assertListResult[T any](result *[]*T) bool { return result != nil }
// or generic helper:
func listOf[T any]() *[]*T { return new([]*T) }
users := listOf[User]()
err := store.List(ctx, users) Try / catch
var users []*User
if err := store.List(ctx, &users); err != nil {
if strings.Contains(err.Error(), "pointer to a slice") {
return fmt.Errorf("caller bug: List needs &users (*[]*User): %w", err)
}
return err
} Prevention
- Always declare the slice variable and pass its address: List(ctx, &users).
- Use typed wrappers/generic helpers that only expose *[]*T parameters.
- Never reuse the Read-style *T pattern for List calls.
- Cover List calls in unit tests so wrong argument shapes fail immediately.
When it happens
Trigger: Calling memoryModel.List(ctx, result) with result of type []T, *T, *[]T (element not pointer is fine — the check is pointer-to-slice — but *map, struct, or nil fail), or forgetting the & when passing a slice variable.
Common situations: Copy-pasting the Read call pattern (which takes a *T) for List, refactoring List's signature and forgetting the address-of operator, or generics misuse where the result parameter's type was changed.
Understand the failure class
Background: "Must be a positive integer", "Invalid value", "Unsupported": the invalid-argument-value error family, when a library rejects the value you pass — this error's family across 35 libraries.
Related errors
- message passed in is nil
- agent pending: unsupported agent implementation %T
- connect reflected grpc target %s: %w
- reflect grpc target %s: %w
- reflection list services returned %T
AI-assisted analysis of micro/go-micro@24529f1404 (2026-09-01).
Data as JSON: /api/errors/b8a7c933adfeaacf.
Report an issue: GitHub.