{"record":{"id":"7480dd8b4f52d5cc","repo":"kubernetes/kops","slug":"error-deleting-keypair-q-v","errorCode":null,"errorMessage":"error deleting KeyPair %q: %v","messagePattern":"error deleting KeyPair %q: (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"pkg/resources/aws/aws.go","lineNumber":685,"sourceCode":"\t\tvolumes = append(volumes, page.Volumes...)\n\t}\n\n\treturn volumes, nil\n}\n\nfunc DeleteKeypair(cloud fi.Cloud, r *resources.Resource) error {\n\tctx := context.TODO()\n\tc := cloud.(awsup.AWSCloud)\n\n\tid := r.ID\n\n\tklog.V(2).Infof(\"Deleting EC2 Keypair %q\", id)\n\trequest := &ec2.DeleteKeyPairInput{\n\t\tKeyPairId: &id,\n\t}\n\t_, err := c.EC2().DeleteKeyPair(ctx, request)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"error deleting KeyPair %q: %v\", id, err)\n\t}\n\treturn nil\n}\n\nfunc ListKeypairs(cloud fi.Cloud, vpcID, clusterName string) ([]*resources.Resource, error) {\n\tctx := context.TODO()\n\tif !strings.Contains(clusterName, \".\") {\n\t\tklog.Infof(\"cluster %q is legacy (kube-up) cluster; won't delete keypairs\", clusterName)\n\t\treturn nil, nil\n\t}\n\n\tc := cloud.(awsup.AWSCloud)\n\n\tkeypairName := \"kubernetes.\" + clusterName\n\n\tklog.V(2).Infof(\"Listing EC2 Keypairs\")\n\n\t// TODO: We need to match both the name and a prefix","sourceCodeStart":667,"sourceCodeEnd":703,"githubUrl":"https://github.com/kubernetes/kops/blob/4c8573c808a73d578c5eadc86d410646ea0b0d73/pkg/resources/aws/aws.go#L667-L703","documentation":"DeleteKeypair wraps any error from ec2:DeleteKeyPair into this error naming the keypair ID. Unlike volume/subnet deletion, there is no NotFound special-case here, so deleting an already-removed keypair also surfaces as this error. The raw AWS error is embedded via %v.","triggerScenarios":"ec2.DeleteKeyPair fails: keypair already deleted (InvalidKeyPair.NotFound), IAM denial (UnauthorizedOperation), throttling, or transient API failure.","commonSituations":"Re-running cluster deletion after a partial teardown deleted the keypair; IAM policy missing ec2:DeleteKeyPair; concurrent kops runs deleting the same keypair; credential/region mismatch pointing at the wrong account.","solutions":["Check the embedded AWS error code; treat InvalidKeyPair.NotFound as success and skip.","Verify IAM permissions grant ec2:DeleteKeyPair.","Retry with backoff if throttled or a transient AWS error occurred.","Confirm the configured region/account actually contains the keypair ID."],"exampleFix":"// before\nif err != nil { return fmt.Errorf(\"error deleting KeyPair %q: %v\", id, err) }\n// after\nif err != nil {\n  if awsup.AWSErrorCode(err) == \"InvalidKeyPair.NotFound\" { return nil }\n  return fmt.Errorf(\"error deleting KeyPair %q: %v\", id, err)\n}","handlingStrategy":"try-catch","validationCode":"kp, err := ec2Client.DescribeKeyPairs(ctx, &ec2.DescribeKeyPairsInput{KeyPairIds: []string{id}})\nif err != nil || len(kp.KeyPairs) == 0 { return nil } // already gone","typeGuard":"func isNotFound(err error) bool { var ae smithy.APIError; return errors.As(err, &ae) && ae.ErrorCode() == \"InvalidKeyPair.NotFound\" }","tryCatchPattern":"if err != nil {\n  if isNotFound(err) { return nil }\n  if isThrottling(err) { return retryOp() }\n  return fmt.Errorf(\"error deleting KeyPair %q: %w\", id, err)\n}","preventionTips":["Check keypair existence before deleting to make deletion idempotent.","Avoid concurrent kops deletes against the same cluster.","Confirm region/account targeting matches where the keypair lives.","Grant ec2:DeleteKeyPair in the IAM policy."],"tags":["aws","ec2","keypair","deletion"],"backgroundTag":"aws-resource-not-found-on-delete","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"}