vitessio/vitess · error
failed to load flag for %s: %w
Error message
failed to load flag for %s: %w
What it means
BindFlags in go/viperutil/internal/value wraps any error returned by val.Flag(fs) into "failed to load flag for <key>" and panics. Because flag registration happens at startup wiring time, a failure here is considered unrecoverable programmer error: a Registerable value could not produce its pflag definition for the given flag set.
Source
Thrown at go/viperutil/internal/value/value.go:106
for _, alias := range val.Aliases {
v.RegisterAlias(alias, val.Key())
}
if len(val.EnvVars) > 0 {
vars := append([]string{val.Key()}, val.EnvVars...)
_ = v.BindEnv(vars...)
}
}
// BindFlags creates bindings between each value's registry and the given flag
// set. This function will panic if any of the values defines a flag that does
// not exist in the flag set.
func BindFlags(fs *pflag.FlagSet, values ...Registerable) {
for _, val := range values {
flag, err := val.Flag(fs)
switch {
case err != nil:
panic(fmt.Errorf("failed to load flag for %s: %w", val.Key(), err))
case flag == nil:
continue
}
_ = val.Registry().BindPFlag(val.Key(), flag)
if flag.Name != val.Key() {
val.Registry().RegisterAlias(flag.Name, val.Key())
}
}
}
// Static is a static value. Static values register to the Static registry, and
// do not respond to changes to config files. Their Get() method will return the
// same value for the lifetime of the process.
type Static[T any] struct {
*Base[T]
}
View on GitHub (pinned to 01a25a7d17)
Solutions
- Read the wrapped inner error in the panic message — it names the underlying pflag failure; fix that first.
- Ensure each Registerable is bound exactly once per FlagSet; remove duplicate BindFlags calls for the same key.
- Verify no two registered values share the same Key(); rename one of the flags.
- Confirm you pass the same *pflag.FlagSet that the value was designed to register into.
Example fix
// before
fs := pflag.NewFlagSet("cmd", pflag.ContinueOnError)
viperutil.BindFlags(fs, val1)
viperutil.BindFlags(fs, val1) // panics: flag redefined
// after
viperutil.BindFlags(fs, val1) Defensive patterns
Strategy: validation
Validate before calling
seen := map[string]bool{}
for _, v := range values {
if seen[v.Key()] {
panic(fmt.Sprintf("duplicate flag key %q passed to BindFlags", v.Key()))
}
seen[v.Key()] = true
} Try / catch
// BindFlags panics; wrap at binary startup
func mustBindFlags(fs *pflag.FlagSet, vals ...viperutil.Registerable) {
defer func() {
if r := recover(); r != nil {
log.Error("flag binding failed", slog.Any("panic", r))
os.Exit(1)
}
}()
viperutil.BindFlags(fs, vals...)
} Prevention
- Bind each Registerable exactly once per FlagSet.
- Keep flag keys unique per binary; prefix plugin flags.
- Smoke-test binary startup (with --help) in CI so binding panics surface before deploy.
When it happens
Trigger: Calling viperutil.BindFlags(fs, vals...) where a Registerable's Flag() method returns a non-nil error — e.g. duplicate flag name already registered on fs, invalid flag name characters, or a value type whose flag factory fails.
Common situations: Registering the same flag key twice in one FlagSet ("flag redefined"); building a custom binary that binds both plugin-defined and built-in flags that collide; passing flags registered on multiple different FlagSets to a single BindFlags call.
Related errors
- both the dry-run mode and actual buffering is enabled. To av
- the logging module doesn't specify a log_dir flag
- unsupported profile mode
- --batch-size requires 'direct' ddl_strategy
- --batch-size conflicts with --uuid-list. Batching does not s
AI-assisted analysis of vitessio/vitess@01a25a7d17 (2026-09-01).
Data as JSON: /api/errors/03acc8a63808608e.
Report an issue: GitHub.