{"record":{"id":"b8b5a7047cdf9919","repo":"vitessio/vitess","slug":"symbol-s-was-not-an-interface-but-t","errorCode":null,"errorMessage":"symbol %s was not an interface but %T","messagePattern":"symbol (.+?) was not an interface but %T","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"error","filePath":"go/vt/vtctl/vtctldclient/codegen/main.go","lineNumber":334,"sourceCode":"\t\t}\n\n\t\treturn nil, err\n\t}\n\n\treturn pkg, nil\n}\n\nfunc extractSourceInterface(pkg *packages.Package, name string) (*types.Interface, error) {\n\tobj := pkg.Types.Scope().Lookup(name)\n\tif obj == nil {\n\t\treturn nil, fmt.Errorf(\"no symbol found with name %s\", name)\n\t}\n\n\tswitch t := obj.Type().(type) {\n\tcase *types.Named:\n\t\tiface, ok := t.Underlying().(*types.Interface)\n\t\tif !ok {\n\t\t\treturn nil, fmt.Errorf(\"symbol %s was not an interface but %T\", name, t.Underlying())\n\t\t}\n\n\t\treturn iface, nil\n\tcase *types.Interface:\n\t\treturn t, nil\n\t}\n\n\treturn nil, fmt.Errorf(\"symbol %s was not an interface but %T\", name, obj.Type())\n}\n\nvar vitessProtoRegexp = regexp.MustCompile(`^vitess\\.io.*/proto/.*`)\n\nfunc rewriteProtoImports(pkg *types.Package) string {\n\tif vitessProtoRegexp.MatchString(pkg.Path()) {\n\t\treturn pkg.Name() + \"pb\"\n\t}\n\n\treturn pkg.Name()","sourceCodeStart":316,"sourceCodeEnd":352,"githubUrl":"https://github.com/vitessio/vitess/blob/01a25a7d176f94613b8d59d799f438380a8760e4/go/vt/vtctl/vtctldclient/codegen/main.go#L316-L352","documentation":"After finding the symbol, extractSourceInterface verifies that a *types.Named symbol's underlying type is an interface. This error fires when the named symbol exists but resolves to a concrete type (struct, alias to struct, etc.), so the generator cannot extract a method set to implement.","triggerScenarios":"Passing the name of a struct (e.g. the server implementation type) or other named non-interface type to extractSourceInterface instead of the interface type.","commonSituations":"Confusing the service interface with its implementation struct; a type that used to be an interface was refactored into a struct; passing a proto message type name by mistake.","solutions":["Pass the interface type name, not the concrete implementation struct","Inspect the type: `type X interface{...}` must exist in the package","If the type was recently changed from interface to struct, update the codegen entrypoint to the new interface"],"exampleFix":"// before (struct passed)\ncodegen --source-interface VtctldServerImpl\n// symbol VtctldServerImpl was not an interface but *types.Struct\n// after\ncodegen --source-interface VtctldServer\n","handlingStrategy":"type-guard","validationCode":"// Confirm it is declared as an interface\ngoDoc, _ := exec.Command(\"go\", \"doc\", pkgPath, name).Output()\nisIface := strings.Contains(string(goDoc), \"interface {\")","typeGuard":"func isNamedInterface(t types.Type) (*types.Named, bool) {\n    n, ok := t.(*types.Named)\n    if !ok { return nil, false }\n    _, ok = n.Underlying().(*types.Interface)\n    return n, ok\n}","tryCatchPattern":null,"preventionTips":["Distinguish implementation struct from service interface before passing names","Check 'go doc <pkg> <Name>' output shows an interface"],"tags":["go","codegen","type-system","reflection"],"backgroundTag":"invalid-argument-value","analyzedSha":"01a25a7d176f94613b8d59d799f438380a8760e4","analyzedAt":"2026-09-01T17:28:30.605Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}