kubernetes/kops · error
error deleting Akamai (Linode) SSH key %s(%s): %w
Error message
error deleting Akamai (Linode) SSH key %s(%s): %w
What it means
deleteSSHKey removes a cluster-generated SSH key from the Linode account. Non-'not found' failures from DeleteSSHKey are wrapped with the key name and ID. linodego.IsNotFound is treated as success (already deleted), so this error means a real API failure while deleting.
Source
Thrown at pkg/resources/linode/resources.go:287
}
}
return resourceTrackers, nil
}
// deleteSSHKey deletes an Akamai (Linode) SSH key.
func deleteSSHKey(cloud fi.Cloud, tracker *resources.Resource) error {
c := cloud.(cloudlinode.LinodeCloud)
keyID, err := parseTrackerIntID(tracker)
if err != nil {
return err
}
if err := c.Client().DeleteSSHKey(context.Background(), keyID); err != nil {
if linodego.IsNotFound(err) {
return nil
}
return fmt.Errorf("error deleting Akamai (Linode) SSH key %s(%s): %w", tracker.Name, tracker.ID, err)
}
return nil
}
// deleteVPC deletes an Akamai (Linode) VPC.
func deleteVPC(cloud fi.Cloud, tracker *resources.Resource) error {
c := cloud.(cloudlinode.LinodeCloud)
vpcID, err := parseTrackerIntID(tracker)
if err != nil {
return err
}
if err := c.Client().DeleteVPC(context.Background(), vpcID); err != nil {
if linodego.IsNotFound(err) {
return nil
}
return fmt.Errorf("error deleting Akamai (Linode) VPC %s(%s): %w", tracker.Name, tracker.ID, err)View on GitHub (pinned to 4c8573c808)
Solutions
- Use an API token with full read/write scopes for kops delete
- Retry the delete; it is idempotent because not-found is tolerated
- Check rate limits and back off before retrying
- Confirm the key ID exists under account > SSH keys in Linode Cloud Manager
- Inspect the wrapped Linode API error status
Example fix
// before
if err := c.Client().DeleteSSHKey(context.Background(), keyID); err != nil {
if linodego.IsNotFound(err) {
return nil
}
return fmt.Errorf("error deleting Akamai (Linode) SSH key %s(%s): %w", tracker.Name, tracker.ID, err)
}
// after
if err := c.Client().DeleteSSHKey(context.Background(), keyID); err != nil {
if linodego.IsNotFound(err) {
return nil
}
if linodego.ErrCode(err) == 429 {
// retry after backoff
}
return fmt.Errorf("error deleting Akamai (Linode) SSH key %s(%s): %w", tracker.Name, tracker.ID, err)
} Defensive patterns
Strategy: retry
Validate before calling
// Ensure token has write scopes before delete operations curl -sS -H "Authorization: Bearer $LINODE_TOKEN" https://api.linode.com/v4/profile/grants | jq .global
Type guard
func isNotFound(err error) bool { return linodego.IsNotFound(err) } Try / catch
if err := c.Client().DeleteSSHKey(ctx, keyID); err != nil {
if linodego.IsNotFound(err) { return nil }
if linodego.ErrCode(err) == 429 { /* backoff and retry */ }
return fmt.Errorf("error deleting Akamai (Linode) SSH key %s(%s): %w", tracker.Name, tracker.ID, err)
} Prevention
- Use full read/write tokens for kops delete
- Treat 404 as success (kops already does)
- Back off on rate limits
- Don't share tokens with reduced scopes for cleanup jobs
When it happens
Trigger: c.Client().DeleteSSHKey(ctx, keyID) fails with 401/403 (insufficient token scopes — write access required), network error, 429 rate limit, or the key ID becoming invalid between listing and deletion.
Common situations: Read-only API token used for cluster deletion; corporate proxy blocking DELETE requests; rate limiting when deleting a large cluster with many resources; concurrent deletion by another operator.
Related errors
- error listing Akamai (Linode) SSH keys: %w
- error deleting Akamai (Linode) VPC %s(%s): %w
- error deleting Akamai (Linode) instance %s(%s): %w
- error listing Akamai (Linode) VPC subnets for VPC %s(%d): %w
- error deleting Akamai (Linode) subnet %s(%s): %w
AI-assisted analysis of kubernetes/kops@4c8573c808 (2026-09-05).
Data as JSON: /api/errors/97d88bb7893861df.
Report an issue: GitHub.