{"record":{"id":"d57846af9402c874","repo":"kubernetes/kops","slug":"error-reading-keyset-q-v","errorCode":null,"errorMessage":"error reading keyset %q: %v","messagePattern":"error reading keyset %q: (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"upup/pkg/fi/clientset_castore.go","lineNumber":117,"sourceCode":"\t\t\tki.PrivateKey = privateKey\n\t\t}\n\n\t\tkeyset.Items[key.Id] = ki\n\t}\n\n\tkeyset.Primary = keyset.Items[FindPrimary(o).Id]\n\n\treturn keyset, nil\n}\n\n// loadKeyset gets the named Keyset and the format of the Keyset.\nfunc (c *ClientsetCAStore) loadKeyset(ctx context.Context, name string) (*Keyset, error) {\n\to, err := c.clientset.Keysets(c.namespace).Get(ctx, name, metav1.GetOptions{})\n\tif err != nil {\n\t\tif errors.IsNotFound(err) {\n\t\t\treturn nil, nil\n\t\t}\n\t\treturn nil, fmt.Errorf(\"error reading keyset %q: %v\", name, err)\n\t}\n\n\tkeyset, err := parseKeyset(o)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn keyset, nil\n}\n\n// FindPrimary returns the primary KeysetItem in the Keyset\nfunc FindPrimary(keyset *kops.Keyset) *kops.KeysetItem {\n\tvar primary *kops.KeysetItem\n\tvar primaryVersion *big.Int\n\n\tprimaryId := keyset.Spec.PrimaryID\n\n\tfor i := range keyset.Spec.Keys {\n\t\titem := &keyset.Spec.Keys[i]","sourceCodeStart":99,"sourceCodeEnd":135,"githubUrl":"https://github.com/kubernetes/kops/blob/4c8573c808a73d578c5eadc86d410646ea0b0d73/upup/pkg/fi/clientset_castore.go#L99-L135","documentation":"ClientsetCAStore.loadKeyset fetches the Keyset object from the cluster registry. A non-NotFound error from the API Get is wrapped as 'error reading keyset \"<name>\": <underlying>'. NotFound returns (nil, nil) so this error specifically signals an API/transport/permission failure, not absence. From upup/pkg/fi/clientset_castore.go:117 via FindKeyset.","triggerScenarios":"Keysets(...).Get fails with anything other than IsNotFound: API server unreachable, RBAC denial (keysets forbidden), context timeout/cancellation, invalid namespace.","commonSituations":"kOps hitting a cluster whose API server is down or behind a broken load balancer; kubeconfig with insufficient RBAC to read keysets in the namespace; network partitions during 'kops update cluster' or CA mirroring.","solutions":["Verify cluster API server reachability: kubectl cluster-info / kubectl get keysets -n <namespace>","Check RBAC: ensure the credentials in the kops kubeconfig may get keysets in the kops namespace","Inspect the wrapped underlying error for timeout vs forbidden and fix connectivity or credentials accordingly","Retry the operation if the underlying error is transient (e.g. connection refused, timeouts)"],"exampleFix":"// before\nkeyset, _ := store.FindKeyset(ctx, name)\n// after: surface and handle transient errors\nkeyset, err := store.FindKeyset(ctx, name)\nif err != nil {\n\treturn fmt.Errorf(\"find keyset: %w\", err) // underlying cause preserved\n}","handlingStrategy":"retry","validationCode":"// pre-flight: ensure API + RBAC allow reading keysets\nif _, err := kubeClient.Keysets(ns).List(ctx, metav1.ListOptions{}); err != nil {\n\treturn fmt.Errorf(\"cannot read keysets in %s: %w\", ns, err)\n}","typeGuard":null,"tryCatchPattern":"keyset, err := store.FindKeyset(ctx, name)\nif err != nil {\n\tif strings.Contains(err.Error(), \"error reading keyset\") {\n\t\t// transient API failure: backoff and retry\n\t}\n\treturn err\n}","preventionTips":["Pre-flight check RBAC for keysets get in the kops namespace","Use retry/backoff around FindKeyset for transient API errors","Keep kubeconfig credentials current to avoid auth-related failures"],"tags":["go","kubernetes","api-server","keyset"],"backgroundTag":"kubernetes-api-get-failed","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"}