kubernetes/kops · error
no keypair ID for %q
Error message
no keypair ID for %q
What it means
The node discovery service builder builds a JWKS from the 'service-account' keypair. It first looks up the keypair ID in NodeupConfig.KeypairIDs; older kOps versions had a bug leaving KeypairID unpopulated for the node role, so when the map entry is empty this error is returned and the discovery-service task fails.
Source
Thrown at nodeup/pkg/model/discovery_service.go:108
ClientKey: keyResource,
ClientCA: caResource,
RegisterName: id.Name,
RegisterNamespace: id.Namespace,
JWKS: jwks,
}
c.AddTask(registerTask)
return nil
}
func findJWKSForServiceAccount(ctx context.Context, keypairIDs map[string]string, keystore fi.KeystoreReader) ([]nodetasks.JSONWebKey, error) {
var jwks []nodetasks.JSONWebKey
name := "service-account"
keypairID := keypairIDs[name]
if keypairID == "" {
// kOps bug where KeypairID was not populated for the node role.
return nil, fmt.Errorf("no keypair ID for %q", name)
}
keyset, err := keystore.FindKeyset(ctx, name)
if err != nil {
return nil, err
}
if keyset == nil {
return nil, fmt.Errorf("keyset %q not found", name)
}
for _, item := range keyset.Items {
if item.DistrustTimestamp != nil {
continue
}
if item.Certificate == nil || item.Certificate.Subject.CommonName != "service-account" {
continue
}
View on GitHub (pinned to 4c8573c808)
Solutions
- Re-run `kops update cluster --refresh-cluster-issue-certificates` / `kops update cluster` to regenerate nodeup config with populated KeypairIDs
- Ensure a service-account key exists: `kops get keypairs service-account --type secrets` ; if missing, re-issue via `kops update cluster`
- Run `kops upgrade cluster` and re-apply so the node role's KeypairID is populated
- Regenerate the node's bootstrap config with a current kops binary
Example fix
# regenerate config so KeypairIDs are populated kops update cluster mycluster.example.com --yes --admin kops rolling-update cluster mycluster.example.com --yes
Defensive patterns
Strategy: validation
Validate before calling
// before building the discovery service, ensure the keypair ID is populated
kpID := nodeupConfig.KeypairIDs["service-account"]
if kpID == "" {
// regenerate nodeup config: kops update cluster <cluster> --yes
return fmt.Errorf("service-account keypair ID missing in nodeup config; re-run kops update cluster")
} Try / catch
jwks, err := findJWKSForServiceAccount(ctx, keypairIDs, keystore)
if err != nil {
if strings.Contains(err.Error(), "no keypair ID") {
// known kOps bug for old node roles: regenerate bootstrap config and retry
return fmt.Errorf("stale nodeup config (missing KeypairID); re-run kops update cluster: %w", err)
}
return err
} Prevention
- Regenerate nodeup config with a current kops binary after upgrading clusters
- Verify `kops get instancegroup` output includes the node role keypair IDs before rolling updates
- Keep the service-account keypair present in cluster state; never hand-edit NodeupConfig
- Run `kops update cluster` after any kOps version upgrade before restarting nodes
When it happens
Trigger: findJWKSForServiceAccount is called (from discovery_service Build) with keypairIDs["service-account"] empty — i.e. the node's NodeupConfig was generated by a kOps version that did not populate KeypairID for the node role, or the service-account keypair was never created/registered.
Common situations: Upgrading an old cluster where node bootstrap config predates KeypairIDs population; cluster state missing the service-account key; running nodeup from a newer binary against stale nodeup config generated by a buggy older kOps.
Related errors
- no keypair ID for %q
- building nodeConfig for instanceGroup: %w
- error finding contained version
- no keypairID for %q
- did not find keypair %s for %s
AI-assisted analysis of kubernetes/kops@4c8573c808 (2026-09-05).
Data as JSON: /api/errors/136b510f20610a8d.
Report an issue: GitHub.