{"record":{"id":"cddee52d711a6482","repo":"kubernetes/kops","slug":"parsing-keyset-q-w","errorCode":null,"errorMessage":"parsing keyset %q: %w","messagePattern":"parsing keyset %q: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"upup/pkg/fi/clientset_castore.go","lineNumber":199,"sourceCode":"\n// ListKeysets implements CAStore::ListKeysets\nfunc (c *ClientsetCAStore) ListKeysets() (map[string]*Keyset, error) {\n\tctx := context.TODO()\n\titems := map[string]*Keyset{}\n\n\t{\n\t\tlist, err := c.clientset.Keysets(c.namespace).List(ctx, metav1.ListOptions{})\n\t\tif err != nil {\n\t\t\treturn nil, fmt.Errorf(\"error listing Keysets: %v\", err)\n\t\t}\n\n\t\tfor i := range list.Items {\n\t\t\tkeyset := &list.Items[i]\n\t\t\tswitch keyset.Spec.Type {\n\t\t\tcase kops.SecretTypeKeypair:\n\t\t\t\titem, err := parseKeyset(keyset)\n\t\t\t\tif err != nil {\n\t\t\t\t\treturn nil, fmt.Errorf(\"parsing keyset %q: %w\", keyset.Name, err)\n\t\t\t\t}\n\n\t\t\t\titems[keyset.Name] = item\n\n\t\t\tcase kops.SecretTypeSecret:\n\t\t\t\tcontinue // Ignore - this is handled by ClientsetSecretStore\n\t\t\tdefault:\n\t\t\t\treturn nil, fmt.Errorf(\"unhandled secret type %q: %v\", keyset.Spec.Type, err)\n\t\t\t}\n\t\t}\n\t}\n\n\treturn items, nil\n}\n\n// StoreKeyset implements CAStore::StoreKeyset\nfunc (c *ClientsetCAStore) StoreKeyset(ctx context.Context, name string, keyset *Keyset) error {\n\treturn c.storeKeyset(ctx, name, keyset)","sourceCodeStart":181,"sourceCodeEnd":217,"githubUrl":"https://github.com/kubernetes/kops/blob/4c8573c808a73d578c5eadc86d410646ea0b0d73/upup/pkg/fi/clientset_castore.go#L181-L217","documentation":"Within ListKeysets, each listed Keyset is decoded via parseKeyset; a per-item parse failure is wrapped as 'parsing keyset \"<name>\": <underlying>' and aborts the whole listing. The underlying cause is usually the certificate/private-key PEM errors from parseKeyset. At upup/pkg/fi/clientset_castore.go:199.","triggerScenarios":"One or more Keyset objects in the namespace contain public or private material that fails PEM parsing, so parseKeyset returns an error during the ListKeysets loop.","commonSituations":"A single corrupted or manually-edited Keyset (e.g. a malformed CA) breaking cluster-wide CA mirroring and any command that enumerates keysets.","solutions":["Identify the named keyset from the message and inspect its material via kubectl get keyset <name> -o yaml -n <namespace>","Fix or re-issue the corrupted keypair's material, or delete/recreate the corrupt Keyset object","Restore the object from etcd/backup, then re-run the list/mirror operation"],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":"// audit stored keysets before listing/mirroring\nkeysets, _ := kubeClient.Keysets(ns).List(ctx, metav1.ListOptions{})\nfor _, ks := range keysets.Items {\n\tfor _, k := range ks.Spec.Keys {\n\t\tif len(k.PublicMaterial) > 0 && !isPEMCertificate(k.PublicMaterial) {\n\t\t\treturn fmt.Errorf(\"keyset %s has corrupt certificate material\", ks.Name)\n\t\t}\n\t}\n}","typeGuard":"func isPEMCertificate(b []byte) bool {\n\tblock, _ := pem.Decode(b)\n\treturn block != nil && block.Type == \"CERTIFICATE\"\n}","tryCatchPattern":"items, err := store.ListKeysets()\nif err != nil {\n\tif strings.Contains(err.Error(), \"parsing keyset\") {\n\t\t// extract keyset name from the message, quarantine it, retry\n\t}\n\treturn err\n}","preventionTips":["Audit keyset material validity after manual cluster edits","Back up keysets before upgrades/downgrades","Rotate rather than patch corrupted keypairs"],"tags":["go","ca","keyset","deserialization"],"backgroundTag":"invalid-pem-certificate","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"}