{"record":{"id":"06d2311a09d09667","repo":"kubernetes/kops","slug":"private-key-not-provided-for-primary-item","errorCode":null,"errorMessage":"private key not provided for primary item","messagePattern":"private key not provided for primary item","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"upup/pkg/fi/ca.go","lineNumber":204,"sourceCode":"func NewKeyset(cert *pki.Certificate, privateKey *pki.PrivateKey) (*Keyset, error) {\n\tkeyset := &Keyset{\n\t\tItems: map[string]*KeysetItem{},\n\t}\n\t_, err := keyset.AddItem(cert, privateKey, true)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\treturn keyset, nil\n}\n\n// AddItem adds an item to the keyset\nfunc (k *Keyset) AddItem(cert *pki.Certificate, privateKey *pki.PrivateKey, primary bool) (item *KeysetItem, err error) {\n\tif cert == nil {\n\t\treturn item, fmt.Errorf(\"no certificate provided\")\n\t}\n\tif privateKey == nil && primary {\n\t\treturn item, fmt.Errorf(\"private key not provided for primary item\")\n\t}\n\n\tif !primary && k.Primary == nil {\n\t\treturn item, fmt.Errorf(\"cannot add secondary item when no existing primary item\")\n\t}\n\n\thighestId := big.NewInt(0)\n\tfor id := range k.Items {\n\t\titemId, ok := big.NewInt(0).SetString(id, 10)\n\t\tif ok && highestId.Cmp(itemId) < 0 {\n\t\t\thighestId = itemId\n\t\t}\n\t}\n\n\t// Make sure any subsequently created items will have ids that compare higher.\n\t// If setting a primary, make sure its id doesn't compare lower than existing items.\n\tidNumber := pki.BuildPKISerial(time.Now().UnixNano())\n\tif cert.Certificate.SerialNumber.Cmp(idNumber) <= 0 &&","sourceCodeStart":186,"sourceCodeEnd":222,"githubUrl":"https://github.com/kubernetes/kops/blob/4c8573c808a73d578c5eadc86d410646ea0b0d73/upup/pkg/fi/ca.go#L186-L222","documentation":"AddItem validates that a primary keyset item always carries a certificate AND a private key. When privateKey is nil but primary=true, kOps would end up with a primary keypair it cannot use for signing, so construction aborts with 'private key not provided for primary item'. It is an argument-validation guard inside upup/pkg/fi/ca.go:204.","triggerScenarios":"Calling Keyset.AddItem(cert, nil, true), or building a keyset via NewKeyset/parsing paths where a cert was parsed successfully but the PEM private key was absent or failed to parse.","commonSituations":"Rotating a CA/keypair from a bundle that contains only the certificate (public .crt/.pem) without the matching private key; a secrets store entry with public material but empty private material; passing a placeholder nil key in test code.","solutions":["Provide the matching pki.PrivateKey along with the certificate when primary=true","If only a certificate is intended, call AddItem with primary=false after a primary item exists","Verify the source PEM/key material actually contains a PRIVATE KEY block, not just a CERTIFICATE block","Fix upstream loaders so private material is parsed before AddItem is invoked"],"exampleFix":"// before\nkeyset.AddItem(cert, nil, true)\n// after\nprivateKey, err := pki.ParsePEMPrivateKey(privateKeyPEM)\nif err != nil { return err }\nkeyset.AddItem(cert, privateKey, true)","handlingStrategy":"validation","validationCode":"if cert == nil || privateKey == nil {\n\treturn fmt.Errorf(\"primary item requires both certificate and private key\")\n}\nitem, err := keyset.AddItem(cert, privateKey, true)","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Always pair the certificate with its parsed private key before calling AddItem","Use primary=false for cert-only additions once a primary exists","Unit-test keyset construction with real PEM fixtures"],"tags":["go","ca","keyset","validation"],"backgroundTag":"missing-private-key","analyzedSha":"4c8573c808a73d578c5eadc86d410646ea0b0d73","analyzedAt":"2026-09-05T04:13:19.212Z","contentChangedAt":"2026-09-05T04:13:19.212Z","schemaVersion":2},"datasetVersion":"2026-09-12T07:17:12.445Z"}