vitessio/vitess · error

symbol NewAuthenticator must be of type `func() Authenticato

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.

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)

Solutions

  1. Change the plugin to export `func NewAuthenticator() rbac.Authenticator` exactly — no parameters, single interface return.
  2. Configure constructor arguments through plugin state or environment instead of constructor parameters.
  3. Rebuild the plugin against the exact same version/commit of the vtadmin rbac package the host binary uses so interface types are identical.
  4. 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

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

Related errors


AI-assisted analysis of vitessio/vitess@01a25a7d17 (2026-09-01). Data as JSON: /api/errors/9a1417e75e4a0874. Report an issue: GitHub.