kubernetes/kops · error

did not find keypair %s for %s

Error message

did not find keypair %s for %s

What it means

The keyset exists, but the specific item (certificate+key pair) addressed by the keypairID from NodeupConfig.KeypairIDs is not in keyset.Items. The node is pinned to a keypair ID that was rotated away or deleted from the state store.

Source

Thrown at nodeup/pkg/model/context.go:402

	// keypair so that the node will be updated when the primary keypair does
	// not match the one that we are using.
	keypairID := c.NodeupConfig.KeypairIDs[name]
	if keypairID == "" {
		// kOps bug where KeypairID was not populated for the node role.
		return fmt.Errorf("no keypair ID for %q", name)
	}

	keyset, err := c.KeyStore.FindKeyset(ctx.Context(), name)
	if err != nil {
		return err
	}
	if keyset == nil {
		return fmt.Errorf("keyset %q not found", name)
	}

	item := keyset.Items[keypairID]
	if item == nil {
		return fmt.Errorf("did not find keypair %s for %s", keypairID, name)
	}

	if includeCert {
		certificate := item.Certificate
		if certificate == nil {
			return fmt.Errorf("certificate %q not found", name)
		}

		cert, err := certificate.AsString()
		if err != nil {
			return err
		}

		ctx.AddTask(&nodetasks.File{
			Path:           p + ".crt",
			Contents:       fi.NewStringResource(cert),
			Type:           nodetasks.FileType_File,
			Mode:           s("0600"),

View on GitHub (pinned to 4c8573c808)

Solutions

  1. Re-run `kops update cluster --yes` so node configs reference the current primary keypair ID, then rolling-update the nodes
  2. Check available IDs with `kops get keypairs <name> -o yaml` and ensure old keypairs weren't pruned before nodes were updated
  3. Increase keyset retention (or re-issue) with `kops create keypair <name>` so the referenced ID exists again
  4. Restart nodeup after config refresh so it picks up the new KeypairIDs
Defensive patterns

Strategy: validation

Validate before calling

keyset, _ := keyStore.FindKeyset(ctx, name)
if keyset != nil && keyset.Items[nodeupConfig.KeypairIDs[name]] == nil {
    return fmt.Errorf("keypair %s for %s pruned; refresh node config or re-issue keypair", nodeupConfig.KeypairIDs[name], name)
}

Try / catch

if err := c.BuildCertificatePairTask(ctx, name, path, filename, owner, nil); err != nil {
    var pinErr = "did not find keypair"
    if strings.Contains(err.Error(), pinErr) {
        klog.Warningf("pinned keypair retired for %s; refresh nodeup config / re-issue keypair", name)
    }
    return err
}

Prevention

When it happens

Trigger: keyset.Items[keypairID] is nil because the keypairID recorded in nodeup config was retired by `kops delete keypair`/rotation pruning, or the nodeup config was generated before a rotation that removed old keypairs.

Common situations: After certificate rotation with retention cleanup, nodes that haven't updated their config still reference pruned keypair IDs; restoring a state store that lacks historical keypairs.

Related errors


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