{"record":{"id":"c13015b71b11382d","repo":"kubernetes/kops","slug":"error-listing-akamai-linode-vpcs-w-c13015","errorCode":null,"errorMessage":"error listing Akamai (Linode) VPCs: %w","messagePattern":"error listing Akamai \\(Linode\\) VPCs: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"upup/pkg/fi/cloudup/linodetasks/vpc.go","lineNumber":59,"sourceCode":"\nfunc (v *VPC) CompareWithID() *string {\n\tif v.ID == nil {\n\t\treturn nil\n\t}\n\tid := strconv.Itoa(fi.ValueOf(v.ID))\n\treturn new(id)\n}\n\nfunc (v *VPC) Find(c *fi.CloudupContext) (*VPC, error) {\n\tcloud := c.T.Cloud.(linode.LinodeCloud)\n\tlistOptions, err := linode.ListOptionsForLabel(fi.ValueOf(v.Name))\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tvpcs, err := cloud.Client().ListVPCs(c.Context(), listOptions)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"error listing Akamai (Linode) VPCs: %w\", err)\n\t}\n\n\tvar found *linodego.VPC\n\tname := fi.ValueOf(v.Name)\n\tfor i := range vpcs {\n\t\tcandidate := &vpcs[i]\n\t\tif candidate.Label != name {\n\t\t\tcontinue\n\t\t}\n\t\tif v.Region != nil && candidate.Region != fi.ValueOf(v.Region) {\n\t\t\tcontinue\n\t\t}\n\t\tif found != nil {\n\t\t\treturn nil, fmt.Errorf(\"found multiple Akamai (Linode) VPCs named %q\", name)\n\t\t}\n\t\tfound = candidate\n\t}\n","sourceCodeStart":41,"sourceCodeEnd":77,"githubUrl":"https://github.com/kubernetes/kops/blob/4c8573c808a73d578c5eadc86d410646ea0b0d73/upup/pkg/fi/cloudup/linodetasks/vpc.go#L41-L77","documentation":"This error wraps a failure from the Linode API ListVPCs call made by the VPC task's Find() when it searches for an existing VPC matching the task's label. It means the discovery/list phase failed before any matching logic ran; the raw linodego error (auth, network, rate limit, server error) is preserved via %w.","triggerScenarios":"ListVPCs returns an error: invalid or expired API token (401), token lacking vpcs:read_only scope (403), API rate limiting (429), network connectivity failure, or a 500 from the Linode API while filtering by label via ListOptionsForLabel.","commonSituations":"Running kops update with credentials rotated/expired; corporate proxy or DNS outage blocking api.linode.com; heavy automation hitting the Linode API rate limit; token created without VPC read scope.","solutions":["Verify LINODE_TOKEN / API token validity and that it includes vpcs:read scope","Check network connectivity/proxy settings to https://api.linode.com/v4","Wait out Linode API rate limits (429) and reduce concurrent kops/API activity, then retry","Retry on transient 5xx errors - Find() is read-only and safe to re-run","Upgrade linodego/kops if the error indicates an API schema change"],"exampleFix":"// before: no pre-flight credential check\nvpcs, err := cloud.Client().ListVPCs(c.Context(), listOptions)\n// after: validate token once at target creation\nif _, err := client.GetAccount(c.Context()); err != nil {\n    return nil, fmt.Errorf(\"linode API token invalid: %w\", err)\n}\nvpcs, err := cloud.Client().ListVPCs(c.Context(), listOptions)","handlingStrategy":"retry","validationCode":"// Pre-flight check before the update run:\nfunc checkLinodeAuth(ctx context.Context, client *linodego.Client) error {\n    if _, err := client.GetAccount(ctx); err != nil {\n        return fmt.Errorf(\"linode API token invalid or lacks vpcs:read scope: %w\", err)\n    }\n    return nil\n}","typeGuard":"func isRetryableAPIError(err error) bool {\n    var apiErr *linodego.Error\n    if errors.As(err, &apiErr) {\n        return apiErr.Code == 429 || apiErr.Code >= 500\n    }\n    return false\n}","tryCatchPattern":"if err := run(); err != nil {\n    if isRetryableAPIError(err) {\n        time.Sleep(backoff)\n        return run()\n    }\n    var apiErr *linodego.Error\n    if errors.As(err, &apiErr) && (apiErr.Code == 401 || apiErr.Code == 403) {\n        return fmt.Errorf(\"fix LINODE_TOKEN / scopes: %w\", err)\n    }\n    return err\n}","preventionTips":["Validate LINODE_TOKEN before long update runs","Request tokens with vpcs:read scope included","Throttle concurrent automation to avoid 429 rate limits","Ensure egress/proxy access to api.linode.com","Retry read-only Find() operations on 5xx - they are side-effect free"],"tags":["linode","vpc","list","api-error","network"],"backgroundTag":"linode-api-list-failed","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"}