kubernetes/kops · error

found multiple NatGateways with id %q

Error message

found multiple NatGateways with id %q

What it means

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.

Source

Thrown at upup/pkg/fi/cloudup/awstasks/natgateway.go:200

	}

	return nil, nil
}

func findNatGatewayById(ctx context.Context, cloud awsup.AWSCloud, id string) (*ec2types.NatGateway, error) {
	request := &ec2.DescribeNatGatewaysInput{}
	request.NatGatewayIds = []string{id}
	response, err := cloud.EC2().DescribeNatGateways(ctx, request)
	if err != nil {
		return nil, fmt.Errorf("error listing NatGateway %q: %v", id, err)
	}

	if response == nil || len(response.NatGateways) == 0 {
		klog.V(2).Infof("Unable to find NatGateway %q", id)
		return nil, nil
	}
	if len(response.NatGateways) != 1 {
		return nil, fmt.Errorf("found multiple NatGateways with id %q", id)
	}
	return &response.NatGateways[0], nil
}

func findNatGatewayFromRouteTable(ctx context.Context, cloud awsup.AWSCloud, routeTable *RouteTable) (*ec2types.NatGateway, error) {
	// Find via route on private route table
	if routeTable.ID != nil {
		klog.V(2).Infof("trying to match NatGateway via RouteTable %s", *routeTable.ID)
		rt, err := findRouteTableByID(ctx, cloud, *routeTable.ID)
		if err != nil {
			return nil, fmt.Errorf("error finding associated RouteTable to NatGateway: %v", err)
		}

		if rt != nil {
			var natGatewayIDs []*string
			natGatewayIDsSeen := map[string]bool{}
			for _, route := range rt.Routes {
				if route.NatGatewayId != nil && route.State != ec2types.RouteStateBlackhole && !natGatewayIDsSeen[*route.NatGatewayId] {

View on GitHub (pinned to 4c8573c808)

Solutions

  1. Re-run the operation — usually a transient API anomaly
  2. Check for proxies or mocks in front of the EC2 API that might duplicate results
  3. If reproducible, inspect the raw DescribeNatGateways response and report to AWS support / kops maintainers

Example fix

// before: trusting a duplicated response
// after: dedupe by ID before the count assertion
seen := map[string]bool{}
var uniq []ec2types.NatGateway
for _, g := range response.NatGateways {
  if !seen[*g.NatGatewayId] { seen[*g.NatGatewayId] = true; uniq = append(uniq, g) }
}
Defensive patterns

Strategy: type-guard

Validate before calling

// assert single result before use
if len(response.NatGateways) != 1 { return fmt.Errorf("expected exactly 1 NatGateway for id %s, got %d", id, len(response.NatGateways)) }

Type guard

func exactlyOne(gws []ec2types.NatGateway) *ec2types.NatGateway {
  if len(gws) == 1 { return &gws[0] }
  return nil
}

Try / catch

gw, err := findNatGatewayById(ctx, cloud, id)
if err != nil && strings.Contains(err.Error(), "found multiple NatGateways with id") {
  // transient/anomalous API response — retry once, then investigate
}

Prevention

When it happens

Trigger: 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).

Common situations: Practically only seen during AWS API anomalies, mocked/test EC2 implementations, or custom clients returning duplicate pages; rarely in production.

Understand the failure class

Background: "invalid response format", "malformed payload", "missing data field": when an API returns 200 but the response shape is wrong — this error's family across 23 libraries.

Related errors


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