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
- Add the primary item first: AddItem(primaryCert, primaryKey, true), then add secondaries
- When rebuilding, locate the item flagged as primary (or the one whose id equals keyset.Spec.PrimaryId) and add it before the rest
- 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
- Build keysets in primary-first order, not map-iteration order
- Resolve the primary id from keyset.Spec.PrimaryId before inserting items
- Add an ordering assertion in tests when rebuilding keysets from storage
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
- private key not provided for primary item
- parsing keyset %q: %w
- error loading certificate %s/%s: %v
- error loading private key %s/%s: %v
- error reading keyset %q: %v
AI-assisted analysis of kubernetes/kops@4c8573c808 (2026-09-05).
Data as JSON: /api/errors/f9c1a8f4f27c5ac2.
Report an issue: GitHub.