{"record":{"id":"967a880c4ca6a584","repo":"kubernetes/kops","slug":"error-creating-sshcredential-v","errorCode":null,"errorMessage":"error creating SSHCredential: %v","messagePattern":"error creating SSHCredential: (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"upup/pkg/fi/clientset_castore.go","lineNumber":277,"sourceCode":"\tcreate := false\n\tclient := c.clientset.SSHCredentials(c.namespace)\n\tsshCredential, err := client.Get(ctx, \"admin\", metav1.GetOptions{})\n\tif err != nil {\n\t\tif errors.IsNotFound(err) {\n\t\t\tsshCredential = nil\n\t\t} else {\n\t\t\treturn fmt.Errorf(\"error reading SSHCredential: %v\", err)\n\t\t}\n\t}\n\tif sshCredential == nil {\n\t\tsshCredential = &kops.SSHCredential{}\n\t\tsshCredential.Name = \"admin\"\n\t\tcreate = true\n\t}\n\tsshCredential.Spec.PublicKey = publicKey\n\tif create {\n\t\tif _, err := client.Create(ctx, sshCredential, metav1.CreateOptions{}); err != nil {\n\t\t\treturn fmt.Errorf(\"error creating SSHCredential: %v\", err)\n\t\t}\n\t} else {\n\t\tif _, err := client.Update(ctx, sshCredential, metav1.UpdateOptions{}); err != nil {\n\t\t\treturn fmt.Errorf(\"error updating SSHCredential: %v\", err)\n\t\t}\n\t}\n\treturn nil\n}\n\n// deleteSSHCredential deletes the SSHCredential from the registry.\nfunc (c *ClientsetCAStore) deleteSSHCredential(ctx context.Context) error {\n\tclient := c.clientset.SSHCredentials(c.namespace)\n\terr := client.Delete(ctx, \"admin\", metav1.DeleteOptions{})\n\tif err != nil {\n\t\treturn fmt.Errorf(\"error deleting SSHCredential: %v\", err)\n\t}\n\treturn nil\n}","sourceCodeStart":259,"sourceCodeEnd":295,"githubUrl":"https://github.com/kubernetes/kops/blob/4c8573c808a73d578c5eadc86d410646ea0b0d73/upup/pkg/fi/clientset_castore.go#L259-L295","documentation":"addSSHCredential creates the 'admin' SSHCredential via client.Create when no existing object was found. Any Create failure is wrapped as 'error creating SSHCredential: %v'. It means the API server refused to persist the new SSH credential object.","triggerScenarios":"First AddSSHPublicKey call for a cluster where the credential does not exist and Create fails: AlreadyExists race (another process created it), RBAC denial on create, invalid object/namespace, or API server error.","commonSituations":"Concurrent `kops create sshpublickey` invocations racing to create the same 'admin' credential; restricted service account; quota/admission webhooks rejecting the object.","solutions":["If the cause is AlreadyExists, re-run the command so it takes the Update path","Check RBAC allows create on sshcredentials.kops.k8s.io","Verify the kops namespace exists in the cluster","Check admission webhooks/quotas if the cause is a rejection other than auth"],"exampleFix":"// before\nif err := store.AddSSHPublicKey(ctx, pub); err != nil { return err }\n// after (handle create-vs-exists race)\nif err := store.AddSSHPublicKey(ctx, pub); err != nil {\n\tif strings.Contains(err.Error(), \"already exists\") {\n\t\treturn nil // another writer created it; update happens on next run\n\t}\n\treturn err\n}","handlingStrategy":"retry","validationCode":"// confirm namespace exists and you can read credentials\nif err := clientset.SSHCredentials(ns).Delete(ctx, \"__probe__\", metav1.DeleteOptions{}); err != nil && !apierrors.IsNotFound(err) && !apierrors.IsForbidden(err) {\n\treturn fmt.Errorf(\"api access problem: %w\", err)\n}","typeGuard":"func isAlreadyExists(err error) bool { return apierrors.IsAlreadyExists(err) }","tryCatchPattern":"if err := store.AddSSHPublicKey(ctx, pub); err != nil {\n\tif isAlreadyExists(err) { return nil } // concurrent creator won; update next run\n\treturn err\n}","preventionTips":["Do not run concurrent `kops create sshpublickey` for the same cluster","Check the wrapped cause for AlreadyExists and switch to the update path","Ensure the kops namespace exists before first write","Grant create on sshcredentials.kops.k8s.io"],"tags":["kubernetes","ssh","create","rbac"],"backgroundTag":"kubernetes-api-write-failed","analyzedSha":"4c8573c808a73d578c5eadc86d410646ea0b0d73","analyzedAt":"2026-09-05T04:13:19.212Z","contentChangedAt":"2026-09-05T04:13:19.212Z","schemaVersion":2},"datasetVersion":"2026-09-12T12:17:11.808Z"}