{"record":{"id":"162eaeb0f9a319cd","repo":"kubernetes/kops","slug":"found-multiple-natgateways-with-id-q","errorCode":null,"errorMessage":"found multiple NatGateways with id %q","messagePattern":"found multiple NatGateways with id %q","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"upup/pkg/fi/cloudup/awstasks/natgateway.go","lineNumber":200,"sourceCode":"\t}\n\n\treturn nil, nil\n}\n\nfunc findNatGatewayById(ctx context.Context, cloud awsup.AWSCloud, id string) (*ec2types.NatGateway, error) {\n\trequest := &ec2.DescribeNatGatewaysInput{}\n\trequest.NatGatewayIds = []string{id}\n\tresponse, err := cloud.EC2().DescribeNatGateways(ctx, request)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"error listing NatGateway %q: %v\", id, err)\n\t}\n\n\tif response == nil || len(response.NatGateways) == 0 {\n\t\tklog.V(2).Infof(\"Unable to find NatGateway %q\", id)\n\t\treturn nil, nil\n\t}\n\tif len(response.NatGateways) != 1 {\n\t\treturn nil, fmt.Errorf(\"found multiple NatGateways with id %q\", id)\n\t}\n\treturn &response.NatGateways[0], nil\n}\n\nfunc findNatGatewayFromRouteTable(ctx context.Context, cloud awsup.AWSCloud, routeTable *RouteTable) (*ec2types.NatGateway, error) {\n\t// Find via route on private route table\n\tif routeTable.ID != nil {\n\t\tklog.V(2).Infof(\"trying to match NatGateway via RouteTable %s\", *routeTable.ID)\n\t\trt, err := findRouteTableByID(ctx, cloud, *routeTable.ID)\n\t\tif err != nil {\n\t\t\treturn nil, fmt.Errorf(\"error finding associated RouteTable to NatGateway: %v\", err)\n\t\t}\n\n\t\tif rt != nil {\n\t\t\tvar natGatewayIDs []*string\n\t\t\tnatGatewayIDsSeen := map[string]bool{}\n\t\t\tfor _, route := range rt.Routes {\n\t\t\t\tif route.NatGatewayId != nil && route.State != ec2types.RouteStateBlackhole && !natGatewayIDsSeen[*route.NatGatewayId] {","sourceCodeStart":182,"sourceCodeEnd":218,"githubUrl":"https://github.com/kubernetes/kops/blob/4c8573c808a73d578c5eadc86d410646ea0b0d73/upup/pkg/fi/cloudup/awstasks/natgateway.go#L182-L218","documentation":"After DescribeNatGateways by a single ID, the code asserts exactly one result. EC2 should return at most one gateway per ID, so more than one result indicates an unexpected API response and the code refuses to proceed.","triggerScenarios":"DescribeNatGateways called with request.NatGatewayIds = [id] returns len(response.NatGateways) > 1, i.e. the API returned multiple NatGateway entries for one ID (response==nil or empty is handled separately).","commonSituations":"Practically only seen during AWS API anomalies, mocked/test EC2 implementations, or custom clients returning duplicate pages; rarely in production.","solutions":["Re-run the operation — usually a transient API anomaly","Check for proxies or mocks in front of the EC2 API that might duplicate results","If reproducible, inspect the raw DescribeNatGateways response and report to AWS support / kops maintainers"],"exampleFix":"// before: trusting a duplicated response\n// after: dedupe by ID before the count assertion\nseen := map[string]bool{}\nvar uniq []ec2types.NatGateway\nfor _, g := range response.NatGateways {\n  if !seen[*g.NatGatewayId] { seen[*g.NatGatewayId] = true; uniq = append(uniq, g) }\n}","handlingStrategy":"type-guard","validationCode":"// assert single result before use\nif len(response.NatGateways) != 1 { return fmt.Errorf(\"expected exactly 1 NatGateway for id %s, got %d\", id, len(response.NatGateways)) }","typeGuard":"func exactlyOne(gws []ec2types.NatGateway) *ec2types.NatGateway {\n  if len(gws) == 1 { return &gws[0] }\n  return nil\n}","tryCatchPattern":"gw, err := findNatGatewayById(ctx, cloud, id)\nif err != nil && strings.Contains(err.Error(), \"found multiple NatGateways with id\") {\n  // transient/anomalous API response — retry once, then investigate\n}","preventionTips":["Retry once on anomalous DescribeNatGateways responses","Avoid custom proxies/mocks in front of EC2 in production tooling"],"tags":["aws","ec2","api-response","natgateway"],"backgroundTag":"unexpected-api-response-shape","analyzedSha":"4c8573c808a73d578c5eadc86d410646ea0b0d73","analyzedAt":"2026-09-05T04:13:19.212Z","contentChangedAt":"2026-09-05T04:13:19.212Z","schemaVersion":2},"datasetVersion":"2026-09-12T12:17:11.808Z"}