vitessio/vitess · error
unknown vtctld client protocol: %s
Error message
unknown vtctld client protocol: %s
What it means
The vtctldclient package creates clients through a registry keyed by an explicit protocol string; New() returns this error when the passed protocol has no registered factory. Unlike the legacy client, the protocol is a parameter chosen by the caller (usually a flag in the consuming binary). It is a configuration/linkage error, not a network error.
Source
Thrown at go/vt/vtctl/vtctldclient/client.go:63
if _, ok := registry[name]; ok {
log.Fatalf("Register: %s already registered", name)
}
registry[name] = factory
}
// New returns a VtctldClient for the given protocol, connected to a
// VtctldServer on the given addr. This function returns an error if no client
// factory was registered for the given protocol.
//
// This is a departure from vtctlclient's New, which relies on a flag in the
// global namespace to determine the protocol to use. Instead, we require
// users to specify their own flag in their own (hopefully not global) namespace
// to determine the protocol to pass into here.
func New(ctx context.Context, protocol string, addr string) (VtctldClient, error) {
factory, ok := registry[protocol]
if !ok {
return nil, fmt.Errorf("unknown vtctld client protocol: %s", protocol)
}
return factory(ctx, addr)
}
View on GitHub (pinned to 01a25a7d17)
Solutions
- Blank-import the implementation: _ "vitess.io/vitess/go/vt/vtctl/vtctldclient/grpcvtctldclient"
- Correct the protocol flag value (typically "grpc") passed to vtctldclient.New
- Check for typos and case sensitivity in the protocol string
- Regenerate/rebuild any vtctldclient codegen'd client so the registry initialization is present
Example fix
// before client, err := vtctldclient.New(ctx, "gprc", addr) // after import _ "vitess.io/vitess/go/vt/vtctl/vtctldclient/grpcvtctldclient" client, err := vtctldclient.New(ctx, "grpc", addr)
Defensive patterns
Strategy: validation
Validate before calling
import _ "vitess.io/vitess/go/vt/vtctl/vtctldclient/grpcvtctldclient"
if protocol != "grpc" {
return fmt.Errorf("unsupported protocol %q", protocol)
} Type guard
func validVtctldProtocol(p string) bool { return p == "grpc" } Try / catch
client, err := vtctldclient.New(ctx, protocol, addr)
if err != nil {
if strings.Contains(err.Error(), "unknown vtctld client protocol") {
return fmt.Errorf("check --vtctld_grpc_protocol and grpcvtctldclient import: %w", err)
}
return err
} Prevention
- Validate the protocol flag in PreRunE before calling New
- Blank-import grpcvtctldclient wherever vtctldclient is used
- Keep protocol strings in one shared constant to avoid typos
When it happens
Trigger: Calling vtctldclient.New(ctx, protocol, addr) where protocol is not a key in registry — e.g. passing "grpc" without importing the grpc client package so its init never registers, or a typo like "gprc".
Common situations: Flag default not set or misspelled in a tool embedding vtctldclient; trimmed custom binary missing the grpcvtctldclient import; switching protocol names across Vitess versions.
Related errors
- unknown vtctl client protocol: %v
- --batch-size requires 'direct' ddl_strategy
- --batch-size conflicts with --uuid-list. Batching does not s
- --batch-size only allowed when all queries are CREATE TABLE|
- failed to load static auth plugin. Plugin configured but grp
AI-assisted analysis of vitessio/vitess@01a25a7d17 (2026-09-01).
Data as JSON: /api/errors/3eb3984cfcd6398a.
Report an issue: GitHub.