vitessio/vitess · error
symbol %s was not an interface but %T
Error message
symbol %s was not an interface but %T
What it means
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.
Source
Thrown at go/vt/vtctl/vtctldclient/codegen/main.go:334
}
return nil, err
}
return pkg, nil
}
func extractSourceInterface(pkg *packages.Package, name string) (*types.Interface, error) {
obj := pkg.Types.Scope().Lookup(name)
if obj == nil {
return nil, fmt.Errorf("no symbol found with name %s", name)
}
switch t := obj.Type().(type) {
case *types.Named:
iface, ok := t.Underlying().(*types.Interface)
if !ok {
return nil, fmt.Errorf("symbol %s was not an interface but %T", name, t.Underlying())
}
return iface, nil
case *types.Interface:
return t, nil
}
return nil, fmt.Errorf("symbol %s was not an interface but %T", name, obj.Type())
}
var vitessProtoRegexp = regexp.MustCompile(`^vitess\.io.*/proto/.*`)
func rewriteProtoImports(pkg *types.Package) string {
if vitessProtoRegexp.MatchString(pkg.Path()) {
return pkg.Name() + "pb"
}
return pkg.Name()View on GitHub (pinned to 01a25a7d17)
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
Example fix
// before (struct passed) codegen --source-interface VtctldServerImpl // symbol VtctldServerImpl was not an interface but *types.Struct // after codegen --source-interface VtctldServer
Defensive patterns
Strategy: type-guard
Validate before calling
// Confirm it is declared as an interface
goDoc, _ := exec.Command("go", "doc", pkgPath, name).Output()
isIface := strings.Contains(string(goDoc), "interface {") Type guard
func isNamedInterface(t types.Type) (*types.Named, bool) {
n, ok := t.(*types.Named)
if !ok { return nil, false }
_, ok = n.Underlying().(*types.Interface)
return n, ok
} Prevention
- Distinguish implementation struct from service interface before passing names
- Check 'go doc <pkg> <Name>' output shows an interface
When it happens
Trigger: 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.
Common situations: 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.
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
- error getting %s in %s: %w
- no symbol found with name %s
- expected a named type for %s, got %v
- expected a named type for type argument %d of %s, got %v
- expected a pointer type for %s, got %v
AI-assisted analysis of vitessio/vitess@01a25a7d17 (2026-09-01).
Data as JSON: /api/errors/b8b5a7047cdf9919.
Report an issue: GitHub.