{"record":{"id":"533df5b5864161b9","repo":"vitessio/vitess","slug":"expected-a-named-type-for-type-argument-d-of-s","errorCode":null,"errorMessage":"expected a named type for type argument %d of %s, got %v","messagePattern":"expected a named type for type argument (.+?) of (.+?), got (.+?)","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"error","filePath":"go/vt/vtctl/vtctldclient/codegen/main.go","lineNumber":404,"sourceCode":"\tif typeArgs.Len() == 0 {\n\t\treturn \"\", nil, nil\n\t}\n\n\targs := make([]string, 0, typeArgs.Len())\n\targImports := make([]typeArgImport, 0, typeArgs.Len())\n\n\tfor i := 0; i < typeArgs.Len(); i++ {\n\t\targ := typeArgs.At(i)\n\n\t\tvar prefix string\n\t\tif ptr, ok := arg.(*types.Pointer); ok {\n\t\t\tprefix = \"*\"\n\t\t\targ = ptr.Elem()\n\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 {","sourceCodeStart":386,"sourceCodeEnd":422,"githubUrl":"https://github.com/vitessio/vitess/blob/01a25a7d176f94613b8d59d799f438380a8760e4/go/vt/vtctl/vtctldclient/codegen/main.go#L386-L422","documentation":"renderTypeArgs renders the type arguments of a generic named type. Each type argument must itself be a named type (optionally behind a single pointer) so it can be rendered as <import>.<Name>. This error fires when a type argument is anything else — a basic type, slice, map, or multi-level pointer.","triggerScenarios":"Declaring a method on the source interface whose parameter instantiates a generic with a non-named type argument, e.g. Wrapper[[]byte], Wrapper[string], Wrapper[**T], or Wrapper[map[K]V].","commonSituations":"Using generics in vtctldclient service interfaces with primitive type arguments; refactoring a proto-typed generic to a primitive; index i in the message tells which positional argument of the generic is the problem.","solutions":["Change the offending type argument (position given in the message) to a named type such as a proto message","Remove generics from the interface method parameter if primitives are required","Extend renderTypeArgs in the codegen tool if support for such args is genuinely needed"],"exampleFix":"// before\nGet[T any](ctx context.Context, req Wrapper[string]) error\n// after\nGet[T any](ctx context.Context, req Wrapper[*vtctldatapb.GetRequest]) error\n","handlingStrategy":"validation","validationCode":"// Ensure each generic type argument is a named type\nnamed := t.(*types.Named)\nfor i := 0; i < named.TypeArgs().Len(); i++ {\n    arg := named.TypeArgs().At(i)\n    if _, ok := arg.(*types.Named); !ok {\n        return fmt.Errorf(\"type arg %d (%v) is not named\", i, arg)\n    }\n}","typeGuard":"func hasNamedTypeArgs(t *types.Named) bool {\n    for i := 0; i < t.TypeArgs().Len(); i++ {\n        if _, ok := t.TypeArgs().At(i).(*types.Named); !ok { return false }\n    }\n    return true\n}","tryCatchPattern":null,"preventionTips":["Never instantiate codegen-visible generics with primitives, slices, or maps","Prefer proto pointer types as generic arguments"],"tags":["go","codegen","generics","type-system"],"backgroundTag":"unsupported-argument-type","analyzedSha":"01a25a7d176f94613b8d59d799f438380a8760e4","analyzedAt":"2026-09-01T17:28:30.605Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}