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
- Re-run `kops update cluster --yes` so node configs reference the current primary keypair ID, then rolling-update the nodes
- Check available IDs with `kops get keypairs <name> -o yaml` and ensure old keypairs weren't pruned before nodes were updated
- Increase keyset retention (or re-issue) with `kops create keypair <name>` so the referenced ID exists again
- 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
- Rolling-update nodes before pruning old keypairs (`kops delete keypair` only after full rotation)
- Check `kops get keypairs <name> -o yaml` for available IDs before cleanup
- Keep keyset retention generous in large slow-rolling clusters
- Regenerate nodeup configs after every rotation
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
- no keypairID for %q
- no keypair ID for %q
- key %q did not have primary id set
- building nodeConfig for instanceGroup: %w
- marshalling nodeupConfig: %w
AI-assisted analysis of kubernetes/kops@4c8573c808 (2026-09-05).
Data as JSON: /api/errors/122f625ae422558f.
Report an issue: GitHub.