Field Note — one real failure, the wrong diagnosis, the actual cause, the fix.
A Helm upgrade that rolls itself back is not a Helm bug. It is Helm doing precisely what you told it to do — and the gap between what you told it and what you meant is the whole lesson.
The symptom
The deploy pipeline ran helm upgrade, waited, and reported failure. Minutes later the cluster was serving the previous version as if nothing had happened. helm history showed the new revision appear and then a rollback to the old one, all automatic. The application logs for the new version were already gone with the pods. It looked like Helm had panicked and reverted on its own.
The wrong diagnosis
“Helm is flaky — pin a different version, add a retry.” That treats a symptom as the disease. The rollback was not random and it was not a defect. It was configured behaviour, working exactly as designed.
The actual cause
The upgrade ran with --atomic. That flag has a clear contract: if the release does not become healthy within the timeout, undo everything and return to the last good state. Healthy is defined by --wait — every pod ready, by its own readiness probe, within the deadline. The new version took longer to warm its cache than the readiness probe allowed, so Kubernetes never marked it ready, so Helm concluded the upgrade had failed, so --atomic did the honourable thing and rolled back. Every component behaved correctly. The only thing wrong was the definition of “ready.”
# What was run:
helm upgrade app ./chart --atomic --timeout 2m
# --atomic : on failure, roll back to the previous revision
# --wait : "success" = all pods pass readiness within --timeout
#
# The probe's initialDelay + threshold exceeded 2m during cache warm-up.
# Helm never saw "ready" -> declared failure -> rolled back. As designed.
The fix
Two changes, both about honesty. Make the readiness probe describe real readiness — add a startup probe for the cache-warming phase, so a slow start is not mistaken for a failure. And align the Helm timeout with the worst-case healthy start, not the average one. Keep --atomic. It is not the problem; it is the safety net working. Once “ready” actually meant ready, the rollback stopped firing, because there was nothing to roll back from.
The reframe
The automation did not fail. It obeyed. The bug was upstream of the tool — in what you declared “success” to mean. Most automation incidents are not the machine doing the wrong thing. They are the machine doing exactly the thing you specified, and revealing that your specification was wrong.