{"record":{"id":"0df0b652e84fc3b8","repo":"kubernetes/kops","slug":"error-listing-akamai-linode-volumes-w","errorCode":null,"errorMessage":"error listing Akamai (Linode) volumes: %w","messagePattern":"error listing Akamai \\(Linode\\) volumes: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"pkg/resources/linode/resources.go","lineNumber":120,"sourceCode":"\t\t\tObj:     instance,\n\t\t})\n\t}\n\n\treturn resourceTrackers, nil\n}\n\n// listVolumes lists Akamai (Linode) block storage volumes owned by the cluster.\nfunc listVolumes(cloud fi.Cloud, clusterInfo resources.ClusterInfo) ([]*resources.Resource, error) {\n\tc := cloud.(cloudlinode.LinodeCloud)\n\tclusterTag := cloudlinode.NormalizeLinodeLabel(clusterInfo.Name)\n\tlistOptions, err := cloudlinode.ListOptionsForTags(fmt.Sprintf(\"%s:%s\", cloudlinode.TagKubernetesClusterName, clusterTag))\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tvolumes, err := c.Client().ListVolumes(context.Background(), listOptions)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"error listing Akamai (Linode) volumes: %w\", err)\n\t}\n\n\tresourceTrackers := make([]*resources.Resource, 0, len(volumes))\n\tfor _, volume := range volumes {\n\t\tresourceTracker := &resources.Resource{\n\t\t\tName:    volume.Label,\n\t\t\tID:      strconv.Itoa(volume.ID),\n\t\t\tType:    resourceTypeVolume,\n\t\t\tDeleter: deleteVolume,\n\t\t\tObj:     volume,\n\t\t}\n\t\tif volume.LinodeID != nil {\n\t\t\tresourceTracker.Blocked = []string{resourceTypeInstance + \":\" + strconv.Itoa(*volume.LinodeID)}\n\t\t}\n\t\tresourceTrackers = append(resourceTrackers, resourceTracker)\n\t}\n\n\treturn resourceTrackers, nil","sourceCodeStart":102,"sourceCodeEnd":138,"githubUrl":"https://github.com/kubernetes/kops/blob/4c8573c808a73d578c5eadc86d410646ea0b0d73/pkg/resources/linode/resources.go#L102-L138","documentation":"Fires in listVolumes when the Linode API ListVolumes call fails while discovering cluster-tagged block storage volumes during resource discovery/teardown — an API, credentials, or network failure, not an absence of volumes.","triggerScenarios":"c.Client().ListVolumes(ctx, listOptions) errors: bad API token, insufficient scopes, rate limiting, network error, or region filter mismatch producing an API-side rejection.","commonSituations":"Expired LINODE_TOKEN during teardown; Linode API incident; token restricted to read-only scopes while listing works but downstream operations fail.","solutions":["Check the Linode API token and its scopes","Retry after transient API errors or rate limiting","Verify the cluster label normalization matches the volumes' tags"],"exampleFix":null,"handlingStrategy":"retry","validationCode":"if os.Getenv(\"LINODE_TOKEN\") == \"\" {\n    return errors.New(\"LINODE_TOKEN is not set\")\n}","typeGuard":"func isLinodeRateLimit(err error) bool {\n    var le linodego.Error\n    return errors.As(err, &le) && le.Code == 429\n}","tryCatchPattern":"volumes, err := c.Client().ListVolumes(ctx, listOptions)\nif err != nil {\n    if isLinodeRateLimit(err) {\n        time.Sleep(retryAfter)\n        volumes, err = c.Client().ListVolumes(ctx, listOptions)\n    }\n    if err != nil {\n        return fmt.Errorf(\"error listing Akamai (Linode) volumes: %w\", err)\n    }\n}","preventionTips":["Validate the Linode token before teardown begins.","Throttle concurrent Linode API calls during large cluster deletes.","Retry listing after rate-limit windows.","Confirm read/write scopes cover volumes."],"tags":["linode","akamai","api-listing","volumes"],"backgroundTag":"cloud-api-list-failed","analyzedSha":"4c8573c808a73d578c5eadc86d410646ea0b0d73","analyzedAt":"2026-09-05T04:13:19.212Z","contentChangedAt":"2026-09-05T04:13:19.212Z","schemaVersion":2},"datasetVersion":"2026-09-12T07:17:12.445Z"}