kubernetes/kubernetes · error
invalid value for MaxUnavailable: %v
Error message
invalid value for MaxUnavailable: %v
What it means
Wraps a failure from util.UnavailableCount (daemonset_util.go:153) during updatedDesiredNodeCounts (update.go:609). UnavailableCount only errors when GetScaledValueFromIntOrPercent cannot parse the RollingUpdate.MaxUnavailable IntOrString (e.g. a malformed percentage string, empty, or a value that overflows when scaled). For a RollingUpdate DaemonSet this blocks rollout math, so the whole reconcile for that DS fails and requeues.
Source
Thrown at pkg/controller/daemon/update.go:609
logger := klog.FromContext(ctx)
tolerations := daemonPodTolerations(ds)
requiredNodeAffinity := nodeaffinity.NewRequiredNodeAffinity(ds.Spec.Template.Spec.NodeSelector, ds.Spec.Template.Spec.Affinity)
for i := range nodeList {
node := nodeList[i]
wantToRun, _ := nodeShouldRunDaemonPod(logger, node, ds, tolerations, requiredNodeAffinity)
if !wantToRun {
continue
}
desiredNumberScheduled++
if _, exists := nodeToDaemonPods[node.Name]; !exists {
nodeToDaemonPods[node.Name] = nil
}
}
maxUnavailable, err := util.UnavailableCount(ds, desiredNumberScheduled)
if err != nil {
return -1, -1, -1, fmt.Errorf("invalid value for MaxUnavailable: %v", err)
}
maxSurge, err := util.SurgeCount(ds, desiredNumberScheduled)
if err != nil {
return -1, -1, -1, fmt.Errorf("invalid value for MaxSurge: %v", err)
}
// if the daemonset returned with an impossible configuration, obey the default of unavailable=1 (in the
// event the apiserver returns 0 for both surge and unavailability)
if desiredNumberScheduled > 0 && maxUnavailable == 0 && maxSurge == 0 {
logger.Info("DaemonSet is not configured for surge or unavailability, defaulting to accepting unavailability", "daemonset", klog.KObj(ds))
maxUnavailable = 1
}
logger.V(5).Info("DaemonSet with maxSurge and maxUnavailable", "daemonset", klog.KObj(ds), "maxSurge", maxSurge, "maxUnavailable", maxUnavailable)
return maxSurge, maxUnavailable, desiredNumberScheduled, nil
}
type historiesByRevision []*apps.ControllerRevisionView on GitHub (pinned to b882c60b40)
Solutions
- Inspect the DS: kubectl get ds <name> -o yaml and check spec.updateStrategy.rollingUpdate.maxUnavailable.
- Set maxUnavailable to a valid int (e.g. 1) or percent string (e.g. "25%") and kubectl apply.
- If generated by Helm/kustomize, fix the template so the field renders a concrete intstr value.
Example fix
// before
spec:
updateStrategy:
type: RollingUpdate
rollingUpdate:
maxUnavailable: "" # unparseable -> error
// after
spec:
updateStrategy:
type: RollingUpdate
rollingUpdate:
maxUnavailable: 1 Defensive patterns
Strategy: validation
Validate before calling
// Validate maxUnavailable before relying on it.
func validMaxUnavailable(v *intstr.IntOrString) bool {
if v == nil { return true }
_, err := intstrutil.GetScaledValueFromIntOrPercent(v, 1, true)
return err == nil
} Try / catch
if _, _, _, err := dsc.updatedDesiredNodeCounts(ctx, ds, nodes, nodeToPods); err != nil {
if strings.Contains(err.Error(), "invalid value for MaxUnavailable") {
// Bad user input; surface as a Deployment/DaemonSet event, do not hot-loop.
dsc.eventRecorder.Eventf(ds, v1.EventTypeWarning, "InvalidMaxUnavailable", err.Error())
return reconcile.Result{RequeueAfter: 30 * time.Second}, nil
}
return reconcile.Result{}, err
} Prevention
- Run kubectl apply --dry-run=server to let admission validate intstr fields.
- Render manifests through templates and assert maxUnavailable is a concrete int/percent in CI.
- Default maxUnavailable explicitly rather than relying on an empty/ambiguous value.
When it happens
Trigger: DS has spec.updateStrategy.type=RollingUpdate but rollingUpdate.maxUnavailable is set to an unparseable value (e.g. "-1%", "abc", "") or an intstr that GetScaledValueFromIntOrPercent rejects for the given desiredNumberScheduled.
Common situations: Hand-edited YAML with a typo in maxUnavailable; a templating/Helm rendering bug emitting an empty field; API version mismatch where the field shape changed.
Related errors
- couldn't get unavailable numbers: %v
- invalid value for MaxSurge: %v
- concurrent-daemonset-syncs must be greater than 0, but got %
- couldn't get node to daemon pod mapping for daemon set %q: %
- couldn't get node for nodeName %q: %v
AI-assisted analysis of kubernetes/kubernetes@b882c60b40 (2026-08-07).
Data as JSON: /api/errors/14225f30c1ede3af.
Report an issue: GitHub.