kubernetes/kops · error

error listing Akamai (Linode) VPC subnets for VPC %s(%d): %w

Error message

error listing Akamai (Linode) VPC subnets for VPC %s(%d): %w

What it means

listSubnets iterates every VPC in the Linode account and calls ListVPCSubnets per VPC. When any per-VPC subnet listing call fails, the error is wrapped with the VPC label and ID. This aborts discovery of cluster subnets during resource cleanup.

Source

Thrown at pkg/resources/linode/resources.go:255

		})
	}

	return resourceTrackers, nil
}

// listSubnets lists Akamai (Linode) VPC subnets attached to the cluster's managed VPC.
func listSubnets(cloud fi.Cloud, clusterInfo resources.ClusterInfo) ([]*resources.Resource, error) {
	c := cloud.(cloudlinode.LinodeCloud)
	vpcs, err := findClusterVPCs(cloud, clusterInfo)
	if err != nil {
		return nil, err
	}

	var resourceTrackers []*resources.Resource
	for _, vpc := range vpcs {
		subnets, err := c.Client().ListVPCSubnets(context.Background(), vpc.ID, nil)
		if err != nil {
			return nil, fmt.Errorf("error listing Akamai (Linode) VPC subnets for VPC %s(%d): %w", vpc.Label, vpc.ID, err)
		}

		for _, subnet := range subnets {
			resourceTrackers = append(resourceTrackers, &resources.Resource{
				Name: subnet.Label,
				ID:   strconv.Itoa(subnet.ID),
				Type: resourceTypeSubnet,
				Deleter: func(cloud fi.Cloud, tracker *resources.Resource) error {
					return deleteSubnet(vpc.ID, cloud, tracker)
				},
				Blocks: []string{resourceTypeVPC + ":" + strconv.Itoa(vpc.ID)},
				Obj:    subnet,
			})
		}
	}

	return resourceTrackers, nil
}

View on GitHub (pinned to 4c8573c808)

Solutions

  1. Re-run 'kops delete cluster' after transient failures; discovery is idempotent
  2. Check API token validity and rate limits
  3. Retry with fewer concurrent operations or after backoff
  4. Verify the VPC still exists in the Linode Cloud Manager
  5. Inspect the wrapped error for the Linode API status code
Defensive patterns

Strategy: retry

Validate before calling

vpcs, err := c.Client().ListVPCs(context.Background(), nil)
if err == nil {
	for _, v := range vpcs { _ = v.ID } // confirm listing works before per-VPC calls
}

Type guard

func isTransient(err error) bool { c := linodego.ErrCode(err); return c == 429 || c >= 500 }

Try / catch

subnets, err := c.Client().ListVPCSubnets(ctx, vpc.ID, nil)
if err != nil && isTransient(err) {
	time.Sleep(backoff); subnets, err = c.Client().ListVPCSubnets(ctx, vpc.ID, nil)
}

Prevention

When it happens

Trigger: c.Client().ListVPCSubnets(ctx, vpc.ID, nil) returns an error for a specific VPC: API auth failure, network error, rate limiting (amplified because one call is made per VPC), or the VPC being concurrently deleted.

Common situations: Long-lived VPCs enumerated during delete while token expires mid-run; 429 rate limits on accounts with many VPCs; VPC removed by another operator between ListVPCs and ListVPCSubnets.

Related errors


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