helm/helm · error
unknown wait strategy (s%s). Valid values are: watcher, hook
Error message
unknown wait strategy (s%s). Valid values are: watcher, hookOnly, legacy
What it means
Returned by Client.GetWaiterWithOptions (pkg/kube/client.go:209) when the strategy string matches none of the three known values: watcher, hookOnly, legacy. Note the message is built by concatenation and contains a stray literal 's' — it renders as "unknown wait strategy (s<value>). Valid values are: ..." — a cosmetic quirk, but the valid-value list it prints is authoritative.
Source
Thrown at pkg/kube/client.go:209
switch strategy {
case LegacyStrategy:
kc, err := c.Factory.KubernetesClientSet()
if err != nil {
return nil, err
}
return &legacyWaiter{kubeClient: kc, ctx: c.WaitContext}, nil
case StatusWatcherStrategy:
return c.newStatusWatcher(opts...)
case HookOnlyStrategy:
sw, err := c.newStatusWatcher(opts...)
if err != nil {
return nil, err
}
return &hookOnlyWaiter{sw: sw}, nil
case "":
return nil, errors.New("wait strategy not set. Choose one of: " + string(StatusWatcherStrategy) + ", " + string(HookOnlyStrategy) + ", " + string(LegacyStrategy))
default:
return nil, errors.New("unknown wait strategy (s" + string(strategy) + "). Valid values are: " + string(StatusWatcherStrategy) + ", " + string(HookOnlyStrategy) + ", " + string(LegacyStrategy))
}
}
func (c *Client) SetWaiter(ws WaitStrategy) error {
return c.SetWaiterWithOptions(ws)
}
func (c *Client) SetWaiterWithOptions(ws WaitStrategy, opts ...WaitOption) error {
var err error
c.Waiter, err = c.GetWaiterWithOptions(ws, opts...)
if err != nil {
return err
}
return nil
}
// New creates a new Client.
func New(getter genericclioptions.RESTClientGetter) *Client {View on GitHub (pinned to 2a29f1770b)
Solutions
- Use the exported constants kube.StatusWatcherStrategy / kube.HookOnlyStrategy / kube.LegacyStrategy instead of raw strings
- Trim and validate the string against the three allowed values before calling SetWaiter
- Fix typos/case: the matcher is exact (watcher, not Watcher or watch)
Example fix
// before
c.SetWaiter(kube.WaitStrategy(strings.TrimSpace(cfg.WaitStrategy)))
// after — validate then use constants
switch strings.TrimSpace(cfg.WaitStrategy) {
case string(kube.StatusWatcherStrategy), string(kube.HookOnlyStrategy), string(kube.LegacyStrategy):
c.SetWaiter(kube.WaitStrategy(strings.TrimSpace(cfg.WaitStrategy)))
default:
return fmt.Errorf("invalid wait strategy %q", cfg.WaitStrategy)
} Defensive patterns
Strategy: validation
Validate before calling
var allowedStrategies = map[kube.WaitStrategy]bool{
kube.StatusWatcherStrategy: true,
kube.HookOnlyStrategy: true,
kube.LegacyStrategy: true,
}
if !allowedStrategies[kube.WaitStrategy(cfg.WaitStrategy)] {
return fmt.Errorf("invalid wait strategy %q (want watcher, hookOnly, or legacy)", cfg.WaitStrategy)
} Type guard
func isValidWaitStrategy(s string) bool {
switch strings.TrimSpace(s) {
case "watcher", "hookOnly", "legacy":
return true
}
return false
} Try / catch
if err := c.SetWaiterWithOptions(ws); err != nil {
if strings.Contains(err.Error(), "unknown wait strategy") {
return fmt.Errorf("config: %q is not a Helm v4 wait strategy (watcher|hookOnly|legacy): %w", ws, err)
}
return err
} Prevention
- Normalize (trim, lowercase-with-care: hookOnly is camel) and validate user input before SetWaiter
- Use exported constants everywhere in code; strings only at the config boundary
- Note the message's stray 's' quirk — don't parse the error text, validate up front
When it happens
Trigger: c.SetWaiter(kube.WaitStrategy("polling")), "watch", "Watcher", or any typo/case variant — anything not exactly watcher, hookOnly, or legacy hits the default branch.
Common situations: Migrating configuration from other tools or old Helm versions with different strategy names; case mismatches; trailing whitespace in config strings; hand-typed values instead of the exported constants.
Related errors
- metadata.name and metadata.generateName cannot both be set
- wait strategy not set. Choose one of: watcher, hookOnly, leg
- failed to create resource: %w
- server-side apply failed for object %s/%s %s: %w
- must either provide a name or specify --generate-name
AI-assisted analysis of helm/helm@2a29f1770b (2026-08-15).
Data as JSON: /api/errors/d3838764219dfc0a.
Report an issue: GitHub.