{"record":{"id":"f1e98b18f6d68ef7","repo":"kubernetes/kops","slug":"error-parsing-ssh-public-key-v","errorCode":null,"errorMessage":"error parsing SSH public key: %v","messagePattern":"error parsing SSH public key: (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"pkg/pki/sshkey.go","lineNumber":50,"sourceCode":"\n// parseSSHPublicKey parses the SSH public key string\nfunc parseSSHPublicKey(publicKey string) (ssh.PublicKey, error) {\n\ttokens := strings.Fields(publicKey)\n\tif len(tokens) < 2 {\n\t\treturn nil, fmt.Errorf(\"error parsing SSH public key: %q\", publicKey)\n\t}\n\n\tsshPublicKeyBytes, err := base64.StdEncoding.DecodeString(tokens[1])\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"error decoding SSH public key: %q err: %s\", publicKey, err)\n\t}\n\tif len(tokens) < 2 {\n\t\treturn nil, fmt.Errorf(\"error decoding SSH public key: %q\", publicKey)\n\t}\n\n\tsshPublicKey, err := ssh.ParsePublicKey(sshPublicKeyBytes)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"error parsing SSH public key: %v\", err)\n\t}\n\treturn sshPublicKey, nil\n}\n\n// colonSeparatedHex formats the byte slice SSH-fingerprint style: hex bytes separated by colons\nfunc colonSeparatedHex(data []byte) string {\n\tsshKeyFingerprint := fmt.Sprintf(\"%x\", data)\n\tvar colonSeparated bytes.Buffer\n\tfor i := 0; i < len(sshKeyFingerprint); i++ {\n\t\tif (i%2) == 0 && i != 0 {\n\t\t\tcolonSeparated.WriteByte(':')\n\t\t}\n\t\tcolonSeparated.WriteByte(sshKeyFingerprint[i])\n\t}\n\n\treturn colonSeparated.String()\n}\n","sourceCodeStart":32,"sourceCodeEnd":68,"githubUrl":"https://github.com/kubernetes/kops/blob/4c8573c808a73d578c5eadc86d410646ea0b0d73/pkg/pki/sshkey.go#L32-L68","documentation":"After decoding, the blob is handed to golang.org/x/crypto/ssh.ParsePublicKey; if the SSH wire-format structure is invalid (bad key type string, wrong field counts, malformed mpints, failed signature/geometry checks) the error is wrapped as 'error parsing SSH public key: %v'.","triggerScenarios":"The base64 blob decodes but is not a well-formed SSH public key: random base64 data, an SSH certificate where a plain key is required, a wire blob from a different key format, or a corrupted/truncated key file.","commonSituations":"Keys mangled by editors (line wrapping inserted into the blob), users generating keys with exotic formats, or passing an ssh-ed25519 certificate (ssh-ed25519-cert-v01@openssh.com) to fingerprinting code expecting a plain key.","solutions":["Regenerate or re-export the public key with `ssh-keygen` and verify `ssh-keygen -l -f id_rsa.pub` succeeds","Ensure the full single line (type + blob + optional comment) is preserved without internal line breaks","If using an SSH certificate, extract the underlying public key first"],"exampleFix":null,"handlingStrategy":"validation","validationCode":"func validateSSHPubKey(s string) error {\n\tf := strings.Fields(s)\n\tif len(f) < 2 {\n\t\treturn fmt.Errorf(\"missing type/blob fields\")\n\t}\n\tb, err := base64.StdEncoding.DecodeString(f[1])\n\tif err != nil {\n\t\treturn fmt.Errorf(\"bad base64: %w\", err)\n\t}\n\tif _, err := ssh.ParsePublicKey(b); err != nil {\n\t\treturn fmt.Errorf(\"bad SSH wire format: %w\", err)\n\t}\n\treturn nil\n}\nif err := validateSSHPubKey(pubKey); err != nil {\n\treturn err\n}\nfp, err := pki.ComputeOpenSSHKeyFingerprint(pubKey)","typeGuard":"func isPlainKeyNotCert(pubKey string) bool {\n\treturn !strings.Contains(pubKey, \"-cert-v01@openssh.com\")\n}","tryCatchPattern":"fp, err := pki.ComputeOpenSSHKeyFingerprint(pubKey)\nvar parseErr *ssh.PassphraseMissingError // example narrowing if using ssh lib directly\nif err != nil {\n\treturn fmt.Errorf(\"cannot fingerprint key: %w\", err)\n}","preventionTips":["Round-trip check with `ssh-keygen -l -f` before feeding keys to kops","Keep public keys as single lines without internal wrapping","Prefer standard ssh-keygen output over hand-assembled key strings"],"tags":["ssh","key-parsing","wire-format"],"backgroundTag":"ssh-public-key-invalid","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"}