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,
}, nilView on GitHub (pinned to 4c8573c808)
Solutions
- 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.
- If building the cluster spec in Go, populate Spec.Networking.Subnets before calling BuildCloudConfig.
- 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
- Always include spec.networking.subnets in Azure cluster manifests; use `kops get cluster -o yaml` to verify before mutating.
- When generating Cluster specs in Go, add a validation step (kops/validation.ValidateCluster) before calling BuildCloudConfig.
- Add a unit test asserting BuildCloudConfig fails fast on empty subnets so regressions surface early.
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
- cluster is not an Azure cluster
- --azure-subscription-id is required
- error populating configuration: %v
- configuration must include Subnets
- error subnets must exist in the cluster
AI-assisted analysis of kubernetes/kops@4c8573c808 (2026-09-05).
Data as JSON: /api/errors/d1e91063475c55d6.
Report an issue: GitHub.