kubernetes/kops · error

cannot add secondary item when no existing primary item

Error message

cannot add secondary item when no existing primary item

What it means

Keyset items are ordered: the first item added must be the primary. AddItem refuses to attach a secondary item (primary=false) while k.Primary is still nil, otherwise the keyset would have no signing primary. Thrown from upup/pkg/fi/ca.go:208.

Source

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

	_, 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 &&
		(!primary || cert.Certificate.SerialNumber.Cmp(highestId) > 0) {
		idNumber = cert.Certificate.SerialNumber
	}

View on GitHub (pinned to 4c8573c808)

Solutions

  1. Add the primary item first: AddItem(primaryCert, primaryKey, true), then add secondaries
  2. When rebuilding, locate the item flagged as primary (or the one whose id equals keyset.Spec.PrimaryId) and add it before the rest
  3. Sort/iterate items deterministically so the primary is inserted first

Example fix

// before
for id, item := range items { keyset.AddItem(item.Certificate, item.PrivateKey, id == primaryID) }
// after
keyset.AddItem(items[primaryID].Certificate, items[primaryID].PrivateKey, true)
for id, item := range items { if id != primaryID { keyset.AddItem(item.Certificate, item.PrivateKey, false) } }
Defensive patterns

Strategy: validation

Validate before calling

if keyset.Primary == nil && !isPrimary {
	return fmt.Errorf("add the primary item before secondaries")
}
item, err := keyset.AddItem(cert, privateKey, isPrimary)

Prevention

When it happens

Trigger: Calling AddItem(cert, key, false) on a freshly created/empty Keyset, or iterating items in non-primary-first order (e.g. sorted by id where the newest/secondary id sorts before the primary).

Common situations: Rebuilding a keyset from storage where items are iterated in map order (random in Go) and a secondary happens to be processed first; loading old keypairs before the primary during migration or mirror operations.

Related errors


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