kubernetes/kops · error

cluster has no subnets

Error message

cluster has no subnets

What it means

BuildCloudConfig assembles the azure-cloud-provider CloudConfig consumed by the Azure cloud-controller-manager and CSI drivers. It requires cluster.Spec.Networking.Subnets to be non-empty because the config derives Location (region) and SubnetName from subnets[0]; with zero subnets there is no valid value for these required cloud-provider fields, so it fails fast with this error instead of publishing a broken secret.

Source

Thrown at upup/pkg/fi/cloudup/azure/cloudconfig.go:57

	RouteTableName              string `json:"routeTableName,omitempty"`
	SecurityGroupName           string `json:"securityGroupName,omitempty"`
	UseInstanceMetadata         bool   `json:"useInstanceMetadata,omitempty"`
	DisableAvailabilitySetNodes bool   `json:"disableAvailabilitySetNodes,omitempty"`
}

// BuildCloudConfig assembles the Azure cloud provider configuration for a
// cluster. kOps publishes the result in the azure-cloud-provider Secret, which
// the cloud-controller-manager and CSI drivers load via the
// --cloud-config-secret-name flag.
func BuildCloudConfig(cluster *kops.Cluster) (*CloudConfig, error) {
	azure := cluster.Spec.CloudProvider.Azure
	if azure == nil {
		return nil, fmt.Errorf("cluster is not an Azure cluster")
	}

	subnets := cluster.Spec.Networking.Subnets
	if len(subnets) == 0 {
		return nil, fmt.Errorf("cluster has no subnets")
	}

	// In kOps the virtual network and the network security group share a name.
	networkName := cluster.AzureNetworkSecurityGroupName()

	return &CloudConfig{
		TenantID:                    azure.TenantID,
		SubscriptionID:              azure.SubscriptionID,
		UseManagedIdentityExtension: true,
		ResourceGroup:               cluster.AzureResourceGroupName(),
		Location:                    subnets[0].Region,
		VnetName:                    networkName,
		SubnetName:                  subnets[0].Name,
		RouteTableName:              cluster.AzureRouteTableName(),
		SecurityGroupName:           networkName,
		UseInstanceMetadata:         true,
		DisableAvailabilitySetNodes: true,
	}, nil

View on GitHub (pinned to 4c8573c808)

Solutions

  1. Add at least one subnet under spec.networking.subnets in the cluster manifest (with a name and region matching your Azure location) before running the operation.
  2. If building the cluster spec in Go, populate Spec.Networking.Subnets before calling BuildCloudConfig.
  3. Verify the cluster spec actually loaded: re-run `kops get cluster -o yaml` and confirm the subnets entries are present, then re-apply/update the cluster.

Example fix

// before (incomplete cluster spec)
spec:
  cloudProvider:
    azure: {}
  networking:
    nonMasqueradeCIDR: 100.64.0.0/10
// after
spec:
  cloudProvider:
    azure: {}
  networking:
    nonMasqueradeCIDR: 100.64.0.0/10
    subnets:
      - name: azure-us-east-1
        type: Public
        region: us-east-1
Defensive patterns

Strategy: validation

Validate before calling

if cluster == nil || cluster.Spec.CloudProvider.Azure == nil {
    return errors.New("not an Azure cluster")
}
if len(cluster.Spec.Networking.Subnets) == 0 {
    return errors.New("cluster spec must define at least one networking subnet before building Azure CloudConfig")
}

Type guard

func hasSubnets(c *kops.Cluster) bool {
    return c != nil && c.Spec.CloudProvider.Azure != nil && len(c.Spec.Networking.Subnets) > 0
}

Prevention

When it happens

Trigger: Calling kops.BuildCloudConfig(cluster) when cluster.Spec.Networking.Subnets is an empty slice or nil (e.g. the cluster spec was constructed programmatically, deserialized incompletely, or the networking section was omitted from the manifest).

Common situations: Hand-writing a minimal Cluster YAML without a networking.subnets section; a controller/automation tool that builds kops.Cluster structs in Go and forgets subnets; a partially applied or truncated cluster manifest where subnets were stripped by a mutating webhook or serialization bug.

Understand the failure class

Background: "is required", "must be set", "missing required field": configuration validation errors across open-source libraries — this error's family across 36 libraries.

Related errors


AI-assisted analysis of kubernetes/kops@4c8573c808 (2026-09-05). Data as JSON: /api/errors/d1e91063475c55d6. Report an issue: GitHub.