kubernetes/kops · error

error creating SSHCredential: %v

Error message

error creating SSHCredential: %v

What it means

addSSHCredential creates the 'admin' SSHCredential via client.Create when no existing object was found. Any Create failure is wrapped as 'error creating SSHCredential: %v'. It means the API server refused to persist the new SSH credential object.

Source

Thrown at upup/pkg/fi/clientset_castore.go:277

	create := false
	client := c.clientset.SSHCredentials(c.namespace)
	sshCredential, err := client.Get(ctx, "admin", metav1.GetOptions{})
	if err != nil {
		if errors.IsNotFound(err) {
			sshCredential = nil
		} else {
			return fmt.Errorf("error reading SSHCredential: %v", err)
		}
	}
	if sshCredential == nil {
		sshCredential = &kops.SSHCredential{}
		sshCredential.Name = "admin"
		create = true
	}
	sshCredential.Spec.PublicKey = publicKey
	if create {
		if _, err := client.Create(ctx, sshCredential, metav1.CreateOptions{}); err != nil {
			return fmt.Errorf("error creating SSHCredential: %v", err)
		}
	} else {
		if _, err := client.Update(ctx, sshCredential, metav1.UpdateOptions{}); err != nil {
			return fmt.Errorf("error updating SSHCredential: %v", err)
		}
	}
	return nil
}

// deleteSSHCredential deletes the SSHCredential from the registry.
func (c *ClientsetCAStore) deleteSSHCredential(ctx context.Context) error {
	client := c.clientset.SSHCredentials(c.namespace)
	err := client.Delete(ctx, "admin", metav1.DeleteOptions{})
	if err != nil {
		return fmt.Errorf("error deleting SSHCredential: %v", err)
	}
	return nil
}

View on GitHub (pinned to 4c8573c808)

Solutions

  1. If the cause is AlreadyExists, re-run the command so it takes the Update path
  2. Check RBAC allows create on sshcredentials.kops.k8s.io
  3. Verify the kops namespace exists in the cluster
  4. Check admission webhooks/quotas if the cause is a rejection other than auth

Example fix

// before
if err := store.AddSSHPublicKey(ctx, pub); err != nil { return err }
// after (handle create-vs-exists race)
if err := store.AddSSHPublicKey(ctx, pub); err != nil {
	if strings.Contains(err.Error(), "already exists") {
		return nil // another writer created it; update happens on next run
	}
	return err
}
Defensive patterns

Strategy: retry

Validate before calling

// confirm namespace exists and you can read credentials
if err := clientset.SSHCredentials(ns).Delete(ctx, "__probe__", metav1.DeleteOptions{}); err != nil && !apierrors.IsNotFound(err) && !apierrors.IsForbidden(err) {
	return fmt.Errorf("api access problem: %w", err)
}

Type guard

func isAlreadyExists(err error) bool { return apierrors.IsAlreadyExists(err) }

Try / catch

if err := store.AddSSHPublicKey(ctx, pub); err != nil {
	if isAlreadyExists(err) { return nil } // concurrent creator won; update next run
	return err
}

Prevention

When it happens

Trigger: First AddSSHPublicKey call for a cluster where the credential does not exist and Create fails: AlreadyExists race (another process created it), RBAC denial on create, invalid object/namespace, or API server error.

Common situations: Concurrent `kops create sshpublickey` invocations racing to create the same 'admin' credential; restricted service account; quota/admission webhooks rejecting the object.

Related errors


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