(Note that the default setup doesn't have this problem because all controller-managers talk only to their local apiserver (over localhost) and apiserver defaults the field. This is not ideal since it prevents running apiservers and controller managers at any ratio other than 1:1.)
We, as a project, could generally take one of two stances here. The extreme form of each position is:
1) Document: in an HA environment, the only safe upgrade path is first kube-apiserver, then controllers, then nodes. (And anyone running webhook admission controllers has to be ready for anything, as webhooks are potentially both clients and part of the core control plane.)
2) Add a rule: clients MUST be backwards compatible by one version. (Under this rule, there is a bug in controller-manager.)
I think the best thing to do is something a bit in the middle. Where we both define a control plane upgrade order, and then define the backwards compatibility requirements for each component. We already do this explicitly for kubelets, which may be up to two versions old and may NOT be newer than the control plane.
I think the required upgrade order has to be something like:
1. Webhooks (which are now required to be backwards compatible by at least one version)
2. kube-apiserver
3. Any aggregated apiservers
4. kube-controller-manager
5. cloud-controller-manager
Under this rule, the bug report in the OP should be directed to whomever did the control plane rollout.
If a roll-back is needed, it'd generally have to happen in the reverse order, which makes things very complicated. To allow roll-back and roll-forward to follow the same order, I think we'd have to adopt a pretty extreme form of position 2). Alternatively, we can take the approach we take with kubelet today: you don't roll kubelet version forward until you're certain you're not going to roll the control plane back. But this means you'd want to progress through those 5 steps slowly.
In general, approach 1) means pain for cluster operators and/or distro providers, and approach 2) means pain for controller / client authors (and a bigger test matrix).
Approach 2) is more consistent with the general Kubernetes "self-healing" philosophy, but (IMO) it requires more coordination from more people to get right (the upgrade has a bug if any of 1000 different people make a mistake; the OP has provided a great example of such a bug) and is therefore less likely to work in practice. It is hard to deterministically improve our testing around running with version-skewed control planes: even the 5 (incomplete) steps I gave already have 5! (120) orderings that perhaps should be tested separately; we'd have to use a randomized approach.