{"record":{"id":"9494c35dd904a9b6","repo":"kubernetes/kops","slug":"error-parsing-ssh-public-key-v-9494c3","errorCode":null,"errorMessage":"error parsing SSH public key: %v","messagePattern":"error parsing SSH public key: (.+?)","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"upup/pkg/fi/clientset_castore.go","lineNumber":301,"sourceCode":"\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}\n\n// AddSSHPublicKey implements CAStore::AddSSHPublicKey\nfunc (c *ClientsetCAStore) AddSSHPublicKey(ctx context.Context, pubkey []byte) error {\n\t_, _, _, _, err := ssh.ParseAuthorizedKey(pubkey)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"error parsing SSH public key: %v\", err)\n\t}\n\n\treturn c.addSSHCredential(ctx, strings.TrimSpace(string(pubkey)))\n}\n\n// FindSSHPublicKeys implements CAStore::FindSSHPublicKeys\nfunc (c *ClientsetCAStore) FindSSHPublicKeys() ([]*kops.SSHCredential, error) {\n\tctx := context.TODO()\n\n\to, err := c.clientset.SSHCredentials(c.namespace).Get(ctx, \"admin\", 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 SSHCredential: %v\", err)\n\t}\n\to.Spec.PublicKey = strings.TrimSpace(o.Spec.PublicKey)\n","sourceCodeStart":283,"sourceCodeEnd":319,"githubUrl":"https://github.com/kubernetes/kops/blob/4c8573c808a73d578c5eadc86d410646ea0b0d73/upup/pkg/fi/clientset_castore.go#L283-L319","documentation":"AddSSHPublicKey validates the supplied key with golang.org/x/crypto/ssh.ParseAuthorizedKey before storing it. If the bytes are not a valid OpenSSH authorized_keys entry, it returns 'error parsing SSH public key: %v'. kOps never persists unparseable keys.","triggerScenarios":"Passing a private key file, a certificate, an empty/truncated buffer, or text with a broken base64 field to AddSSHPublicKey; also caused by reading the wrong file (e.g. id_rsa instead of id_rsa.pub) or Windows line endings/CRLF in the key file.","commonSituations":"`kops create sshpublickey` pointed at a private key instead of the .pub file; copy-pasted key losing characters; key generated by a tool producing non-standard formats (e.g. PuTTY PPK not exported to OpenSSH).","solutions":["Pass the contents of the .pub file (e.g. ~/.ssh/id_rsa.pub), never the private key","Validate locally: `ssh-keygen -l -f mykey.pub` must succeed","Ensure the file has no CRLF line endings and is a single authorized_keys line","Regenerate the key with `ssh-keygen -t ed25519` if the format is non-standard"],"exampleFix":"// before\npub, _ := os.ReadFile(\"~/.ssh/id_rsa\") // private key — parse fails\nstore.AddSSHPublicKey(ctx, pub)\n// after\npub, _ := os.ReadFile(\"~/.ssh/id_rsa.pub\")\nif _, _, _, _, err := ssh.ParseAuthorizedKey(pub); err != nil {\n\treturn fmt.Errorf(\"invalid public key: %w\", err)\n}\nstore.AddSSHPublicKey(ctx, pub)","handlingStrategy":"validation","validationCode":"func validPublicKey(pub []byte) error {\n\tif len(pub) == 0 { return errors.New(\"empty key\") }\n\tif _, _, _, _, err := ssh.ParseAuthorizedKey(pub); err != nil { return err }\n\treturn nil\n}\n// call before AddSSHPublicKey\nif err := validPublicKey(pub); err != nil { return err }","typeGuard":"func isParsedAuthorizedKey(b []byte) bool {\n\t_, _, _, _, err := ssh.ParseAuthorizedKey(b)\n\treturn err == nil\n}","tryCatchPattern":"if err := store.AddSSHPublicKey(ctx, pub); err != nil {\n\tif strings.Contains(err.Error(), \"error parsing SSH public key\") {\n\t\treturn fmt.Errorf(\"not an authorized_keys-format public key: %w\", err)\n\t}\n\treturn err\n}","preventionTips":["Always pass the .pub file contents, never the private key","Validate with `ssh-keygen -l -f key.pub` before uploading","Convert non-OpenSSH formats (PuTTY PPK) to OpenSSH first","Strip CRLF and keep the key on a single line"],"tags":["ssh","validation","key-format"],"backgroundTag":"ssh-public-key-parse-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"}