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
- Re-run 'kops delete cluster' after transient failures; discovery is idempotent
- Check API token validity and rate limits
- Retry with fewer concurrent operations or after backoff
- Verify the VPC still exists in the Linode Cloud Manager
- 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
- Use an account with a modest number of VPCs or accept longer delete times
- Back off on 429s; one subnet call is made per VPC
- Ensure token doesn't expire mid-run
- Verify VPCs aren't concurrently modified by other operators
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
- error listing Akamai (Linode) VPC Subnets: %w
- error deleting Akamai (Linode) VPC %s(%s): %w
- error deleting Akamai (Linode) subnet %s(%s): %w
- Subnet.VPC is required
- Subnet.VPC.ID is required
AI-assisted analysis of kubernetes/kops@4c8573c808 (2026-09-05).
Data as JSON: /api/errors/cfd5f077e714992c.
Report an issue: GitHub.