{"record":{"id":"0235d19b547cae1e","repo":"kubernetes/kops","slug":"error-listing-akamai-linode-ssh-keys-w","errorCode":null,"errorMessage":"error listing Akamai (Linode) SSH keys: %w","messagePattern":"error listing Akamai \\(Linode\\) SSH keys: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"pkg/resources/linode/resources.go","lineNumber":200,"sourceCode":"\t\tif vpc.Label != vpcLabel {\n\t\t\tcontinue\n\t\t}\n\t\tif region != \"\" && vpc.Region != region {\n\t\t\tcontinue\n\t\t}\n\n\t\tclusterVPCs = append(clusterVPCs, vpc)\n\t}\n\n\treturn clusterVPCs, nil\n}\n\n// listSSHKeys lists Akamai (Linode) SSH keys that were generated for the cluster.\nfunc listSSHKeys(cloud fi.Cloud, clusterInfo resources.ClusterInfo) ([]*resources.Resource, error) {\n\tc := cloud.(cloudlinode.LinodeCloud)\n\tkeys, err := c.Client().ListSSHKeys(context.Background(), nil)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"error listing Akamai (Linode) SSH keys: %w\", err)\n\t}\n\n\tkeyLabelPrefix := cloudlinode.NormalizeLinodeLabel(\"kubernetes.\"+clusterInfo.Name) + \"-\"\n\tvar resourceTrackers []*resources.Resource\n\tfor _, key := range keys {\n\t\tif !strings.HasPrefix(key.Label, keyLabelPrefix) {\n\t\t\tcontinue\n\t\t}\n\n\t\tresourceTrackers = append(resourceTrackers, &resources.Resource{\n\t\t\tName:    key.Label,\n\t\t\tID:      strconv.Itoa(key.ID),\n\t\t\tType:    resourceTypeSSHKey,\n\t\t\tDeleter: deleteSSHKey,\n\t\t\tObj:     key,\n\t\t})\n\t}\n","sourceCodeStart":182,"sourceCodeEnd":218,"githubUrl":"https://github.com/kubernetes/kops/blob/4c8573c808a73d578c5eadc86d410646ea0b0d73/pkg/resources/linode/resources.go#L182-L218","documentation":"listSSHKeys in the kOps Linode (Akamai) resource cleanup code enumerates all SSH keys registered with the Linode account via linodego's ListSSHKeys. If that API call fails, the error is wrapped with this message and returned so cluster deletion aborts. It means the Linode API rejected or could not serve the SSH key listing request.","triggerScenarios":"linodego ListSSHKeys returns a non-nil error: invalid or expired API token, network failure, Linode API 4xx/5xx response, or rate limiting during 'kops delete cluster' discovery of cluster resources.","commonSituations":"Expired LINODE_TOKEN with insufficient scopes, corporate proxy/firewall blocking api.linode.com, Linode API outage or 429 rate limit while deleting many resources, wrong API endpoint configured.","solutions":["Verify the Linode API token (LINODE_TOKEN) is valid, unexpired, and has read scopes","Test connectivity to https://api.linode.com/v4/profile from the host","Re-run the delete command after transient API errors; the operation is idempotent","Check Linode status page for API incidents","Enable linodego debug logging to inspect the raw HTTP response"],"exampleFix":"// before\nkeys, err := c.Client().ListSSHKeys(context.Background(), nil)\nif err != nil {\n\treturn nil, fmt.Errorf(\"error listing Akamai (Linode) SSH keys: %w\", err)\n}\n// after\nkeys, err := c.Client().ListSSHKeys(context.Background(), nil)\nif err != nil {\n\tif linodego.ErrCode(err) == 401 {\n\t\treturn nil, fmt.Errorf(\"error listing Akamai (Linode) SSH keys: check LINODE_TOKEN credentials: %w\", err)\n\t}\n\treturn nil, fmt.Errorf(\"error listing Akamai (Linode) SSH keys: %w\", err)\n}","handlingStrategy":"try-catch","validationCode":"// Pre-check credentials before running kops delete\ncurl -sS -H \"Authorization: Bearer $LINODE_TOKEN\" https://api.linode.com/v4/profile | jq .username","typeGuard":"func isLinodeAuthError(err error) bool { return linodego.ErrCode(err) == 401 || linodego.ErrCode(err) == 403 }","tryCatchPattern":"keys, err := c.Client().ListSSHKeys(context.Background(), nil)\nif err != nil {\n\tif isLinodeAuthError(err) { /* fix token, then retry */ }\n\treturn fmt.Errorf(\"error listing Akamai (Linode) SSH keys: %w\", err)\n}","preventionTips":["Keep LINODE_TOKEN valid with read/write scopes before cluster operations","Check Linode API status page before large deletes","Avoid running bulk deletes through restrictive proxies","Retry transient API errors instead of abandoning cleanup"],"tags":["linode","akamai","api-error","ssh-keys","cloud-cleanup"],"backgroundTag":"linode-api-request-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"}