k3s-io/k3s · error
toleration with empty key must have operator 'Exists'
Error message
toleration with empty key must have operator 'Exists'
What it means
validateToleration applies Kubernetes toleration semantics to tolerations k3s reads from the ServiceLB service annotation (servicelb.k3s.io/tolerations): the operator defaults to 'Equal', and a toleration with an empty key is only meaningful as 'tolerate everything' with operator 'Exists'. An empty key with operator Equal (explicit or defaulted) is rejected.
Source
Thrown at pkg/cloudprovider/servicelb.go:734
}
for i := range tolerations {
if err := validateToleration(&tolerations[i]); err != nil {
return nil, fmt.Errorf("validation failed for toleration %d: %v", i, err)
}
}
return tolerations, nil
}
// validateToleration ensures a toleration has valid fields according to its operator.
func validateToleration(toleration *core.Toleration) error {
if toleration.Operator == "" {
toleration.Operator = core.TolerationOpEqual
}
if toleration.Key == "" && toleration.Operator != core.TolerationOpExists {
return errors.New("toleration with empty key must have operator 'Exists'")
}
if toleration.Operator == core.TolerationOpExists && toleration.Value != "" {
return errors.New("toleration with operator 'Exists' must have an empty value")
}
return nil
}
// generateName generates a distinct name for the DaemonSet based on the service name and UID
func generateName(svc *core.Service) string {
name := svc.Name
// ensure that the service name plus prefix and uuid aren't overly long, but
// don't cut the service name at a trailing hyphen.
if len(name) > 48 {
trimlen := 48
for name[trimlen-1] == '-' {
trimlen--View on GitHub (pinned to 6ba341e396)
Solutions
- For a catch-all toleration set operator Exists: `{"operator":"Exists","effect":"NoSchedule"}`
- Otherwise provide a concrete key: `{"key":"node-role.kubernetes.io/control-plane","effect":"NoSchedule"}`
- Validate the annotation JSON against core.Toleration rules before applying the Service
Example fix
# before
kubectl annotate svc my-svc servicelb.k3s.io/tolerations='[{"key":"","effect":"NoSchedule"}]'
# after
kubectl annotate svc my-svc servicelb.k3s.io/tolerations='[{"operator":"Exists","effect":"NoSchedule"}]' Defensive patterns
Strategy: validation
Validate before calling
// validate servicelb tolerations annotation before applying the Service
func tolerationOK(t core.Toleration) bool {
op := t.Operator
if op == "" {
op = core.TolerationOpEqual
}
if t.Key == "" && op != core.TolerationOpExists {
return false // empty key requires Exists
}
if op == core.TolerationOpExists && t.Value != "" {
return false // Exists cannot carry a value
}
return true
} Type guard
func isValidServiceLBToleration(t core.Toleration) bool {
op := t.Operator
if op == "" { op = core.TolerationOpEqual }
return !((t.Key == "" && op != core.TolerationOpExists) || (op == core.TolerationOpExists && t.Value != ""))
} Prevention
- Reuse upstream k8s toleration validation rules when templating annotations
- For catch-all tolerations always write {"operator":"Exists"} Unit-test annotation templates against both validateToleration failure modes
When it happens
Trigger: Annotating a Service with `servicelb.k3s.io/tolerations: '[{"key":"","operator":"Equal","effect":"NoSchedule"}]'`, or omitting the operator on a toleration with no key, e.g. `[{"effect":"NoSchedule"}]`.
Common situations: Writing a catch-all toleration and forgetting that the operator must be Exists; JSON shorthand entries with only an effect field; generated annotations from templates that leave key empty.
Related errors
- toleration with operator 'Exists' must have an empty value
- all cloud-provider functionality disabled by config
- Failed checking netMode
- Initial server URL host is not defined for load balancer
- --server is required
AI-assisted analysis of k3s-io/k3s@6ba341e396 (2026-08-15).
Data as JSON: /api/errors/c4121cadf94d0708.
Report an issue: GitHub.