Skip to content

Topology spread constraints fail with empty zone domain in counts #1384

Description

@justinwalz

Version

Karpenter version: 1.6.6, and 1.7.1
Mode: Self hosted (see below comment, someone reproduced with NAP as well).
Kubernetes version: 1.33
Region: eastus2

Expected Behavior

With topology spread constraint maxSkew: 1 and whenUnsatisfiable: DoNotSchedule, Karpenter should provision nodes in zones that satisfy the constraint.

Current distribution: zone1=2, zone2=1, zone3=1
Expected: Provision in zone2 or zone3 (maxSkew would be 1)

Actual Behavior

Karpenter reports topology constraint as unsatisfiable and refuses to provision nodes. Logs show an unexpected empty string domain in topology counts:

counts = : 0, eastus2-1: 2, eastus2-2: 1, eastus2-3: 1

This appears to cause incorrect maxSkew calculation. My guess here is that the first part of that error string is missing a zone, hence : 0, when others have format $zone: $count.

Steps to Reproduce the Problem

  1. Deploy with topology spread constraints in a zonal region:
topologySpreadConstraints:
  - maxSkew: 1
    topologyKey: topology.kubernetes.io/zone
    whenUnsatisfiable: DoNotSchedule
    labelSelector:
      matchLabels:
        app.kubernetes.io/name: my-name
  1. Scale to create pending pods requiring new nodes

  2. Observe Karpenter refusing to provision despite valid zones available

Resource Specs and Logs

Note, we have two node pools, default and ephemeral (spot instances for cronjob job pods).

In both cases for us, one Deployment, and one Statefulset, both using the default nodepool, caused this error.

{"level":"ERROR","time":"2026-01-27T18:23:45.982Z","logger":"controller","message":"could not schedule pod","commit":"28204ca","controller":"provisioner","namespace":"","name":"","reconcileID":"7b152da1-16b0-41a1-a483-025bfe3f72ca","Pod":{"name":"<REDACTED_POD_NAME>","namespace":"<REDACTED_POD_NAMESPACE>"},"taint":"dedicated=ephemeral:NoSchedule","error":"did not tolerate taint (taint=dedicated=ephemeral:NoSchedule); unsatisfiable topology constraint for topology spread, key=topology.kubernetes.io/zone (counts = : 0, eastus2-1: 1, eastus2-2: 1, eastus2-3: 1, podDomains = topology.kubernetes.io/zone Exists, nodeDomains = topology.kubernetes.io/zone Exists","errorCauses":[{"error":"did not tolerate taint (taint=dedicated=ephemeral:NoSchedule)"},{"error":"unsatisfiable topology constraint for topology spread, key=topology.kubernetes.io/zone (counts = : 0, eastus2-1: 1, eastus2-2: 1, eastus2-3: 1, podDomains = topology.kubernetes.io/zone Exists, nodeDomains = topology.kubernetes.io/zone Exists"}]}

Short-term mitigation

Switching from DoNotSchedule to ScheduleAnyway allowed Karpenter to create a node, and immediately following, saw the event Pod should schedule on: nodeclaim/$name.

I include this because it seems to me that this setting is only really for the kube scheduler, and since karpenter still needed to create a new node to fit, it probably should have been able to do so in the earlier case with DoNotSchedule. In fact, we rely on DoNotSchedule to require karpenter to schedule a new node in another zone, so that we maintain zone spread.

This is what leads me to believe this is a bug in the implementation somewhere.

Community Note

  • Please vote on this issue by adding a 👍 reaction to the original issue to help the community and maintainers prioritize this request
  • Please do not leave "+1" or "me too" comments, they generate extra noise for issue followers and do not help prioritize the request
  • If you are interested in working on this issue or have submitted a pull request, please leave a comment

Metadata

Metadata

Assignees

Labels

kind/bugCategorizes issue or PR as related to a bug.

Type

Fields

No fields configured for Bug.

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions