{"record":{"id":"4cdc638e2ba6ce83","repo":"vitessio/vitess","slug":"expected-a-pointer-type-for-s-got-v","errorCode":null,"errorMessage":"expected a pointer type for %s, got %v","messagePattern":"expected a pointer type for (.+?), got (.+?)","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"error","filePath":"go/vt/vtctl/vtctldclient/codegen/main.go","lineNumber":418,"sourceCode":"\t\t}\n\n\t\targNamed, ok := arg.(*types.Named)\n\t\tif !ok {\n\t\t\treturn \"\", nil, fmt.Errorf(\"expected a named type for type argument %d of %s, got %v\", i, named.Obj().Name(), arg)\n\t\t}\n\n\t\tlocalImport := rewriteProtoImports(argNamed.Obj().Pkg())\n\t\targs = append(args, prefix+localImport+\".\"+argNamed.Obj().Name())\n\t\targImports = append(argImports, typeArgImport{localImport: localImport, pkgPath: argNamed.Obj().Pkg().Path()})\n\t}\n\n\treturn \"[\" + strings.Join(args, \", \") + \"]\", argImports, nil\n}\n\nfunc extractLocalPointerType(v *types.Var) (name string, localImport string, pkgPath string, err error) {\n\tptr, ok := v.Type().(*types.Pointer)\n\tif !ok {\n\t\treturn \"\", \"\", \"\", fmt.Errorf(\"expected a pointer type for %s, got %v\", v.Name(), v.Type())\n\t}\n\n\ttyp, ok := ptr.Elem().(*types.Named)\n\tif !ok {\n\t\treturn \"\", \"\", \"\", fmt.Errorf(\"expected an underlying named type for %s, got %v\", v.Name(), ptr.Elem())\n\t}\n\n\tname = typ.Obj().Name()\n\tlocalImport = rewriteProtoImports(typ.Obj().Pkg())\n\tpkgPath = typ.Obj().Pkg().Path()\n\n\treturn name, localImport, pkgPath, nil\n}\n\nfunc extractRecvType(v *types.Var) (name string, localImport string, pkgPath string, err error) {\n\tnamed, ok := v.Type().(*types.Named)\n\tif !ok {\n\t\treturn \"\", \"\", \"\", fmt.Errorf(\"expected a named type for %s, got %v\", v.Name(), v.Type())","sourceCodeStart":400,"sourceCodeEnd":436,"githubUrl":"https://github.com/vitessio/vitess/blob/01a25a7d176f94613b8d59d799f438380a8760e4/go/vt/vtctl/vtctldclient/codegen/main.go#L400-L436","documentation":"extractLocalPointerType expects an *types.Var to be a pointer to a named type (the codegen templates take proto pointers like *vtctldatapb.X). This error means the variable's type is not a pointer at all, so the generator cannot emit the pointer-based wrapper code.","triggerScenarios":"A method parameter or receiver variable on the processed interface has a value (non-pointer) type — e.g. takes vtctldatapb.Request by value or a plain struct.","commonSituations":"Changing a proto-style API from pointer receivers/params to value semantics then running codegen; a new method added with value-type params; called from main for arguments or from extractRecvType for receiver vars.","solutions":["Change the parameter to a pointer type (*pkg.Type)","Follow Vitess conventions: proto messages are passed as pointers","If value types are intentional, adapt the codegen tool"],"exampleFix":"// before\nfunc (s *Server) Get(req vtctldatapb.GetRequest) error\n// after\nfunc (s *Server) Get(req *vtctldatapb.GetRequest) error\n","handlingStrategy":"type-guard","validationCode":"// Verify params are pointers before codegen\nfor i := 0; i < sig.Params().Len(); i++ {\n    if _, ok := sig.Params().At(i).Type().(*types.Pointer); !ok {\n        return fmt.Errorf(\"param %d is not a pointer\", i)\n    }\n}","typeGuard":"func isPointerToNamed(v *types.Var) bool {\n    p, ok := v.Type().(*types.Pointer)\n    if !ok { return false }\n    _, ok = p.Elem().(*types.Named)\n    return ok\n}","tryCatchPattern":null,"preventionTips":["Follow the Vitess convention: proto messages always passed as pointers","Review interface diffs for accidental value-type params before running codegen"],"tags":["go","codegen","pointers","type-system"],"backgroundTag":"unsupported-parameter-type","analyzedSha":"01a25a7d176f94613b8d59d799f438380a8760e4","analyzedAt":"2026-09-01T17:28:30.605Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}