vitessio/vitess · error
symbol NewAuthenticator must be of type `func()…
Error message
symbol NewAuthenticator must be of type `func() Authenticator`; have %T
What it means
vtadmin loads RBAC authenticator implementations as Go plugins via the plugin package, expecting the plugin to export a symbol `NewAuthenticator` with the exact type `func() Authenticator`. If the symbol exists but has a different signature (including non-zero parameters or different return types), the plugin load fails with this type assertion error. This is how vtadmin enforces the authenticator constructor contract at plugin load time.
Solutions
- Change the plugin to export `func NewAuthenticator() rbac.Authenticator` exactly — no parameters, single interface return.
- Configure constructor arguments through plugin state or environment instead of constructor parameters.
- Rebuild the plugin against the exact same version/commit of the vtadmin rbac package the host binary uses so interface types are identical.
- Verify with `nm` or `go plugin` inspection that NewAuthenticator is exported and its symbol type matches.
Example fix
// before
func NewAuthenticator(cfg map[string]string) *MyAuth { ... }
// after
func NewAuthenticator() rbac.Authenticator {
cfg := loadConfigFromEnv()
return &MyAuth{cfg: cfg}
} Defensive patterns
Strategy: type-guard
Validate before calling
p, err := plugin.Open(path)
if err != nil { return err }
sym, err := p.Lookup("NewAuthenticator")
if err != nil { return err }
if _, ok := sym.(func() rbac.Authenticator); !ok {
return fmt.Errorf("plugin %s: NewAuthenticator has wrong signature", path)
} Type guard
func isValidAuthenticatorPlugin(sym plugin.Symbol) bool {
_, ok := sym.(func() Authenticator)
return ok
} Try / catch
auth, err := rbac.NewAuthenticatorFromPath(path)
if err != nil && strings.Contains(err.Error(), "must be of type") {
return fmt.Errorf("plugin %s incompatible: rebuild against host vtadmin version", path)
} Prevention
- Copy the canonical plugin template so NewAuthenticator has signature func() Authenticator.
- Build plugins with the exact same Go version and vtadmin module version as the host binary.
- Smoke-test plugin loading in CI before deploying.
- Pass configuration via env or plugin state, never constructor parameters.
When it happens
Trigger: Building a custom authenticator plugin whose NewAuthenticator has parameters (e.g., func(cfg map[string]string) Authenticator), returns a concrete type rather than the Authenticator interface, or returns (Authenticator, error).
Common situations: Writing a new plugin after copying an example with a different constructor signature; compiling against a different version of the vtadmin rbac package so the Authenticator interface type differs between plugin and host; exporting the wrong symbol type entirely.
Understand the failure class
- Authentication and authorization failures — expired tokens, bad credentials, and missing scopes.
Related errors
- %w %s
- rule : actions list cannot include wildcard and other…
- rule : clusters list cannot include wildcard and other…
- rule : subjects list cannot include wildcard and other…
- unregistered Authenticator implementation
AI-assisted analysis of vitessio/vitess@01a25a7d17 (2026-09-01).
Data as JSON: /api/errors/9a1417e75e4a0874.
Report an issue: GitHub.
Appendix: source
Thrown at go/vt/vtadmin/rbac/authentication.go:163
defer authenticatorsM.Unlock()
if f, ok := authenticators[path]; ok {
return f(), nil
}
p, err := plugin.Open(path)
if err != nil {
return nil, err
}
sym, err := p.Lookup("NewAuthenticator")
if err != nil {
return nil, err
}
f, ok := sym.(func() Authenticator)
if !ok {
return nil, fmt.Errorf("symbol NewAuthenticator must be of type `func() Authenticator`; have %T", sym)
}
authenticators[path] = f
return f(), nil
}
View on GitHub (pinned to 01a25a7d17)