kubernetes/kops · error

private key not provided for primary item

Error message

private key not provided for primary item

What it means

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.

Source

Thrown at upup/pkg/fi/ca.go:204

func NewKeyset(cert *pki.Certificate, privateKey *pki.PrivateKey) (*Keyset, error) {
	keyset := &Keyset{
		Items: map[string]*KeysetItem{},
	}
	_, err := keyset.AddItem(cert, privateKey, true)
	if err != nil {
		return nil, err
	}

	return keyset, nil
}

// AddItem adds an item to the keyset
func (k *Keyset) AddItem(cert *pki.Certificate, privateKey *pki.PrivateKey, primary bool) (item *KeysetItem, err error) {
	if cert == nil {
		return item, fmt.Errorf("no certificate provided")
	}
	if privateKey == nil && primary {
		return item, fmt.Errorf("private key not provided for primary item")
	}

	if !primary && k.Primary == nil {
		return item, fmt.Errorf("cannot add secondary item when no existing primary item")
	}

	highestId := big.NewInt(0)
	for id := range k.Items {
		itemId, ok := big.NewInt(0).SetString(id, 10)
		if ok && highestId.Cmp(itemId) < 0 {
			highestId = itemId
		}
	}

	// Make sure any subsequently created items will have ids that compare higher.
	// If setting a primary, make sure its id doesn't compare lower than existing items.
	idNumber := pki.BuildPKISerial(time.Now().UnixNano())
	if cert.Certificate.SerialNumber.Cmp(idNumber) <= 0 &&

View on GitHub (pinned to 4c8573c808)

Solutions

  1. Provide the matching pki.PrivateKey along with the certificate when primary=true
  2. If only a certificate is intended, call AddItem with primary=false after a primary item exists
  3. Verify the source PEM/key material actually contains a PRIVATE KEY block, not just a CERTIFICATE block
  4. Fix upstream loaders so private material is parsed before AddItem is invoked

Example fix

// before
keyset.AddItem(cert, nil, true)
// after
privateKey, err := pki.ParsePEMPrivateKey(privateKeyPEM)
if err != nil { return err }
keyset.AddItem(cert, privateKey, true)
Defensive patterns

Strategy: validation

Validate before calling

if cert == nil || privateKey == nil {
	return fmt.Errorf("primary item requires both certificate and private key")
}
item, err := keyset.AddItem(cert, privateKey, true)

Prevention

When it happens

Trigger: 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.

Common situations: 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.

Related errors


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