kubernetes/kops · error

error creating keyset %q: %v

Error message

error creating keyset %q: %v

What it means

When the Keyset does not already exist, storeKeyset calls client.Create; failure is wrapped as 'error creating keyset "<name>": <underlying>'. Most commonly this is AlreadyExists (a race with another writer) or an API/RBAC error, surfaced from upup/pkg/fi/clientset_castore.go:247 via StoreKeyset.

Source

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

	oldKeyset, err := client.Get(ctx, name, metav1.GetOptions{})
	if errors.IsNotFound(err) {
		oldKeyset = nil
		err = nil
	}
	if err == nil {
		if oldKeyset == nil {
			create = true
		} else {
			kopsKeyset.ObjectMeta = oldKeyset.ObjectMeta
		}
	} else {
		return fmt.Errorf("error reading keyset %q: %v", name, err)
	}

	if create {
		if _, err := client.Create(ctx, kopsKeyset, metav1.CreateOptions{}); err != nil {
			return fmt.Errorf("error creating keyset %q: %v", name, err)
		}
	} else {
		if _, err := client.Update(ctx, kopsKeyset, metav1.UpdateOptions{}); err != nil {
			return fmt.Errorf("error updating keyset %q: %v", name, err)
		}
	}
	return nil
}

// addSSHCredential saves the specified SSH Credential to the registry, doing an update or insert
func (c *ClientsetCAStore) addSSHCredential(ctx context.Context, publicKey string) error {
	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 {

View on GitHub (pinned to 4c8573c808)

Solutions

  1. If the wrapped error is AlreadyExists, re-run the operation so storeKeyset takes the Update path, or fetch and merge into the existing keyset
  2. Check RBAC allows creating keysets in the kops namespace
  3. Serialize rotation operations (a single kOps run) to avoid create/update races
  4. Inspect the underlying message for validation failures and fix the keyset payload

Example fix

// before: naive create fails on race
client.Create(ctx, kopsKeyset, metav1.CreateOptions{})
// after: tolerate race by falling back to update
if _, err := client.Create(ctx, kopsKeyset, metav1.CreateOptions{}); err != nil {
	if apierrors.IsAlreadyExists(err) {
		_, err = client.Update(ctx, kopsKeyset, metav1.UpdateOptions{})
	}
	if err != nil { return err }
}
Defensive patterns

Strategy: retry

Validate before calling

// detect likely race before create
if _, err := kubeClient.Keysets(ns).Get(ctx, name, metav1.GetOptions{}); err == nil {
	// keyset exists; use the update path instead of expecting create
}

Type guard

func isAlreadyExists(err error) bool {
	return apierrors.IsAlreadyExists(errors.Unwrap(err)) || strings.Contains(err.Error(), "AlreadyExists")
}

Try / catch

err := store.StoreKeyset(ctx, name, keyset)
if err != nil {
	if strings.Contains(err.Error(), "error creating keyset") && strings.Contains(err.Error(), "AlreadyExists") {
		// re-run so storeKeyset takes the Update path
	}
	return err
}

Prevention

When it happens

Trigger: client.Create fails: the keyset was created concurrently (AlreadyExists), RBAC denies create on keysets, the object is invalid per validation, or the API server rejects the request.

Common situations: Two kOps processes rotating keys at once; service accounts lacking create permission during automation; ObjectMeta/name conflicts after manual keyset creation.

Related errors


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