{"record":{"id":"b8a7c933adfeaacf","repo":"micro/go-micro","slug":"model-result-must-be-a-pointer-to-a-slice","errorCode":null,"errorMessage":"model: result must be a pointer to a slice","messagePattern":"model: result must be a pointer to a slice","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"model/memory.go","lineNumber":147,"sourceCode":"\t\treturn err\n\t}\n\n\tm.mu.Lock()\n\tdefer m.mu.Unlock()\n\n\ttbl := m.tables[schema.Table]\n\tif _, ok := tbl[key]; !ok {\n\t\treturn ErrNotFound\n\t}\n\tdelete(tbl, key)\n\treturn nil\n}\n\nfunc (m *memoryModel) List(ctx context.Context, result interface{}, opts ...QueryOption) error {\n\t// result must be *[]*T\n\trv := reflect.ValueOf(result)\n\tif rv.Kind() != reflect.Pointer || rv.Elem().Kind() != reflect.Slice {\n\t\treturn fmt.Errorf(\"model: result must be a pointer to a slice\")\n\t}\n\tsliceVal := rv.Elem()\n\telemType := sliceVal.Type().Elem() // *T\n\tstructType := elemType\n\tif structType.Kind() == reflect.Pointer {\n\t\tstructType = structType.Elem()\n\t}\n\n\tm.mu.RLock()\n\ts, ok := m.types[structType]\n\tm.mu.RUnlock()\n\tif !ok {\n\t\treturn ErrNotRegistered\n\t}\n\n\tq := ApplyQueryOptions(opts...)\n\n\tm.mu.RLock()","sourceCodeStart":129,"sourceCodeEnd":165,"githubUrl":"https://github.com/micro/go-micro/blob/24529f140421a11a33b6999ab7944f2021cfd69c/model/memory.go#L129-L165","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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."],"exampleFix":"// before\nusers := []*User{}\nerr := store.List(ctx, users) // slice, not pointer\n\n// after\nvar users []*User\nerr := store.List(ctx, &users)","handlingStrategy":"type-guard","validationCode":"// ensure result is *[]*T before calling\nfunc isPtrToSlice(result interface{}) bool {\n    rv := reflect.ValueOf(result)\n    return rv.Kind() == reflect.Pointer && rv.Elem().Kind() == reflect.Slice\n}","typeGuard":"func assertListResult[T any](result *[]*T) bool { return result != nil }\n// or generic helper:\nfunc listOf[T any]() *[]*T { return new([]*T) }\nusers := listOf[User]()\nerr := store.List(ctx, users)","tryCatchPattern":"var users []*User\nif err := store.List(ctx, &users); err != nil {\n    if strings.Contains(err.Error(), \"pointer to a slice\") {\n        return fmt.Errorf(\"caller bug: List needs &users (*[]*User): %w\", err)\n    }\n    return err\n}","preventionTips":["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."],"tags":["model","reflection","api-misuse","types"],"backgroundTag":"invalid-argument-value","analyzedSha":"24529f140421a11a33b6999ab7944f2021cfd69c","analyzedAt":"2026-09-01T02:52:24.923Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T05:18:18.240Z"}