derailed/k9s · warning
did not phase down correctly expecting 0 replicas but got %d
Error message
did not phase down correctly expecting 0 replicas but got %d
What it means
ReplicaSet.diagnose is the VALID-column health check. When rs.Status.Replicas equals 0 but rs.Status.ReadyReplicas is non-zero — the controller reports zero total replicas while some pods still count as ready — it returns 'did not phase down correctly expecting 0 replicas but got N'. The message signals a scale-down whose status counters have not converged (typically pods still terminating or a stale status cache). It is rendered as status text via AsStatus and never returned to the caller as a failure.
Source
Thrown at internal/render/rs.go:102
rs.Name,
computeVulScore(rs.Namespace, rs.Labels, &rs.Spec.Template.Spec),
strconv.Itoa(int(*rs.Spec.Replicas)),
strconv.Itoa(int(rs.Status.Replicas)),
strconv.Itoa(int(rs.Status.ReadyReplicas)),
strings.Join(cos, ","),
strings.Join(imgs, ","),
mapToStr(rs.Labels),
AsStatus(r.diagnose(&rs)),
ToAge(rs.GetCreationTimestamp()),
}
return nil
}
func (ReplicaSet) diagnose(rs *appsv1.ReplicaSet) error {
if rs.Status.Replicas != rs.Status.ReadyReplicas {
if rs.Status.Replicas == 0 {
return fmt.Errorf("did not phase down correctly expecting 0 replicas but got %d", rs.Status.ReadyReplicas)
}
return fmt.Errorf("mismatch desired(%d) vs ready(%d)", rs.Status.Replicas, rs.Status.ReadyReplicas)
}
return nil
}
View on GitHub (pinned to 2d3ccc6ba2)
Solutions
- Wait for terminating pods to finish: kubectl get pods -l <selector> until none remain
- Check finalizers and terminationGracePeriodSeconds keeping pods terminating
- Refresh the view — a stale informer cache can show the mismatch briefly
- If it persists, kubectl describe rs <name> and inspect controller events
Example fix
# before: rs at 0 replicas, pods still terminating kubectl scale rs/myrs --replicas=0 kubectl get pods -l app=myrs # after: wait for the ready counters to converge kubectl rollout status rs/myrs --timeout=60s
Defensive patterns
Strategy: validation
Validate before calling
# catch the condition before it renders
kubectl get rs -o json | jq '.items[] | select(.status.replicas==0 and .status.readyReplicas>0) | {name:.metadata.name, ready:.status.readyReplicas}' Prevention
- Wait for terminating pods to exit before reading RS health (kubectl rollout status rs/<name>)
- Avoid overly long terminationGracePeriodSeconds and stray finalizers
- Refresh before reacting: informer staleness can show the mismatch briefly
- Read the VALID column as transient scale-down state, not a defect
When it happens
Trigger: An RS scaled to 0 (or being deleted) while its pods are still terminating; reading the RS view right after kubectl scale rs/<n> --replicas=0; momentary informer staleness during heavy churn. Any row where status.replicas==0 && status.readyReplicas>0 trips it.
Common situations: Scaling to zero before removing a deployment; CI batches deleting workloads; autoscaler floors at 0; long terminationGracePeriodSeconds or finalizers keeping pods alive.
Related errors
- mismatch desired(%d) vs ready(%d)
- desired %d replicas got %d available
- want %d replicas got %d available
- unexpected status %s
- expected Unstructured, but got %T
AI-assisted analysis of derailed/k9s@2d3ccc6ba2 (2026-08-15).
Data as JSON: /api/errors/0a72648564336753.
Report an issue: GitHub.