kubernetes/kops · error

error deleting KeyPair %q: %v

Error message

error deleting KeyPair %q: %v

What it means

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.

Source

Thrown at pkg/resources/aws/aws.go:685

		volumes = append(volumes, page.Volumes...)
	}

	return volumes, nil
}

func DeleteKeypair(cloud fi.Cloud, r *resources.Resource) error {
	ctx := context.TODO()
	c := cloud.(awsup.AWSCloud)

	id := r.ID

	klog.V(2).Infof("Deleting EC2 Keypair %q", id)
	request := &ec2.DeleteKeyPairInput{
		KeyPairId: &id,
	}
	_, err := c.EC2().DeleteKeyPair(ctx, request)
	if err != nil {
		return fmt.Errorf("error deleting KeyPair %q: %v", id, err)
	}
	return nil
}

func ListKeypairs(cloud fi.Cloud, vpcID, clusterName string) ([]*resources.Resource, error) {
	ctx := context.TODO()
	if !strings.Contains(clusterName, ".") {
		klog.Infof("cluster %q is legacy (kube-up) cluster; won't delete keypairs", clusterName)
		return nil, nil
	}

	c := cloud.(awsup.AWSCloud)

	keypairName := "kubernetes." + clusterName

	klog.V(2).Infof("Listing EC2 Keypairs")

	// TODO: We need to match both the name and a prefix

View on GitHub (pinned to 4c8573c808)

Solutions

  1. Check the embedded AWS error code; treat InvalidKeyPair.NotFound as success and skip.
  2. Verify IAM permissions grant ec2:DeleteKeyPair.
  3. Retry with backoff if throttled or a transient AWS error occurred.
  4. Confirm the configured region/account actually contains the keypair ID.

Example fix

// before
if err != nil { return fmt.Errorf("error deleting KeyPair %q: %v", id, err) }
// after
if err != nil {
  if awsup.AWSErrorCode(err) == "InvalidKeyPair.NotFound" { return nil }
  return fmt.Errorf("error deleting KeyPair %q: %v", id, err)
}
Defensive patterns

Strategy: try-catch

Validate before calling

kp, err := ec2Client.DescribeKeyPairs(ctx, &ec2.DescribeKeyPairsInput{KeyPairIds: []string{id}})
if err != nil || len(kp.KeyPairs) == 0 { return nil } // already gone

Type guard

func isNotFound(err error) bool { var ae smithy.APIError; return errors.As(err, &ae) && ae.ErrorCode() == "InvalidKeyPair.NotFound" }

Try / catch

if err != nil {
  if isNotFound(err) { return nil }
  if isThrottling(err) { return retryOp() }
  return fmt.Errorf("error deleting KeyPair %q: %w", id, err)
}

Prevention

When it happens

Trigger: ec2.DeleteKeyPair fails: keypair already deleted (InvalidKeyPair.NotFound), IAM denial (UnauthorizedOperation), throttling, or transient API failure.

Common situations: 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.

Related errors


AI-assisted analysis of kubernetes/kops@4c8573c808 (2026-09-05). Data as JSON: /api/errors/7480dd8b4f52d5cc. Report an issue: GitHub.