AWS Load Balancer Controller "failed to build model: subnet not found"
Fixes the AWS Load Balancer Controller failing to build the load balancer model because it cannot find subnets. Shows how to check the controller logs, verify subnet tags for auto-discovery, or set explicit subnet IDs on the ingress or service. Reach for it when ingresses or services never get an address.
TL;DR
The controller discovers subnets by tag and found none matching. Tag your subnets with kubernetes.io/cluster/[CLUSTER-NAME] plus the elb or internal-elb role tag, across at least two availability zones, or set explicit subnet IDs with the subnet annotation. Then the model builds and the address appears.
Verbatim error
Failed to build model: failed to resolve subnets: subnet not foundSteps
- Confirm the error and which resource it blocks in the controller logs.
kubectl logs -n kube-system -l app.kubernetes.io/name=aws-load-balancer-controller --tail=200Expected: lines naming your ingress or service with failed to build model and the subnet resolution failure. Note the exact resource name.
- Check whether the resource sets explicit subnets.
kubectl get ingress [INGRESS-NAME] -n [NAMESPACE] -o yaml
kubectl get service [SERVICE-NAME] -n [NAMESPACE] -o yamlExpected: look for the subnets annotation (service.beta.kubernetes.io/aws-load-balancer-subnets). If it names subnet IDs, verify those IDs exist; if it is absent, the controller uses tag-based auto-discovery and your tags are wrong.
- Verify subnet tags for auto-discovery using the AWS CLI.
aws ec2 describe-subnets --filters "Name=tag:kubernetes.io/cluster/[CLUSTER-NAME],Values=owned,shared"Expected: at least two subnets in different availability zones, each also tagged kubernetes.io/role/elb for internet-facing or kubernetes.io/role/internal-elb for internal load balancers. Missing or mistyped tags are the usual cause.
- Fix the tags (or set the explicit annotation), choosing one method per resource.
aws ec2 create-tags --resources [SUBNET-ID] --tags Key [your value] Key [your value]Expected: the subnets now carry both the cluster tag and the role tag. Alternatively, add the subnets annotation with explicit subnet IDs to the ingress or service; do not mix both methods on one resource.
- Watch the controller reconcile and the address appear.
kubectl describe ingress [INGRESS-NAME] -n [NAMESPACE]Expected: the events stop showing the model failure and the status gains a hostname. If the error persists, re-check that the tagged subnets span at least two AZs and match the scheme (internal vs internet-facing).
When to use
- Ingresses or LoadBalancer services never receive an address
- Controller logs show failed to build model with subnet resolution errors
- The failure started after creating subnets, renaming the cluster, or changing tags
When not to use
- The load balancer is created but targets stay unhealthy; that is target-group health, not subnet discovery
- The error names security groups instead of subnets; check the security-group tags and annotations
- You use the in-tree cloud provider, not the AWS Load Balancer Controller
Why it happens
The controller builds an internal model of the desired load balancer before calling AWS, and subnet resolution is the first step. With no explicit subnet annotation it relies entirely on tags; any tag mismatch, wrong cluster name, missing role tag, or subnets in a single AZ, makes resolution return nothing and the model build fails.
Edge cases
- Tag value must be owned or shared; any other value is ignored by discovery.
- Internet-facing load balancers need public subnets with the elb role tag; internal ones need private subnets with internal-elb. Swapped roles fail the same way.
- Shared subnets from another account need the tags on the shared subnet itself, not just in your account's view.
- After fixing tags, the controller retries automatically; do not delete and recreate the ingress, which just resets the backoff.
Provenance
Resolved from the public thread: https://vectle.com/posts/pstxx8Cq0Ca5FDrR_jHBAx8w