{"record":{"id":"2afc9b71650b0f80","repo":"kubernetes/kops","slug":"error-decoding-ssh-public-key-q-err-s","errorCode":null,"errorMessage":"error decoding SSH public key: %q err: %s","messagePattern":"error decoding SSH public key: %q err: (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"pkg/pki/sshkey.go","lineNumber":42,"sourceCode":"\t\"crypto/x509\"\n\t\"encoding/base64\"\n\t\"fmt\"\n\t\"reflect\"\n\t\"strings\"\n\n\t\"golang.org/x/crypto/ssh\"\n)\n\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 {","sourceCodeStart":24,"sourceCodeEnd":60,"githubUrl":"https://github.com/kubernetes/kops/blob/4c8573c808a73d578c5eadc86d410646ea0b0d73/pkg/pki/sshkey.go#L24-L60","documentation":"After the type token, parseSSHPublicKey base64-decodes the second whitespace field; failure here means the blob is not valid base64. The error includes the offending key string and the decode error from base64.StdEncoding.","triggerScenarios":"The second token contains characters outside the standard base64 alphabet (e.g. the key was double-encoded, URL-safe base64 was used, or PEM body lines were pasted instead of the OpenSSH wire blob), or the blob is truncated mid-line.","commonSituations":"Pasting the body of a PEM public key (which is DER base64, not the SSH wire format), or copy/paste introducing newlines/spaces inside the blob field.","solutions":["Regenerate/obtain the key from `ssh-keygen -y -f id_rsa > id_rsa.pub` and use that exact line","Check the base64 blob for embedded whitespace or non-standard characters","Verify you're not passing a PEM-formatted (-----BEGIN PUBLIC KEY-----) key where an OpenSSH-format pub key is expected"],"exampleFix":"// before\n// passing body of a PEM PUBLIC KEY block\nfp, _ := ComputeAWSKeyFingerprint(pemBodyBase64)\n// after\npubBytes, _ := os.ReadFile(\"~/.ssh/id_rsa.pub\") // OpenSSH one-line format\nfp, _ := ComputeAWSKeyFingerprint(string(pubBytes))","handlingStrategy":"validation","validationCode":"func blobIsBase64(pubKey string) bool {\n\tf := strings.Fields(pubKey)\n\tif len(f) < 2 {\n\t\treturn false\n\t}\n\t_, err := base64.StdEncoding.DecodeString(f[1])\n\treturn err == nil\n}\nif !blobIsBase64(pubKey) {\n\treturn fmt.Errorf(\"second field of SSH public key is not valid standard base64\")\n}","typeGuard":null,"tryCatchPattern":"if _, err := pki.ComputeOpenSSHKeyFingerprint(pubKey); err != nil {\n\tif strings.Contains(err.Error(), \"error decoding SSH public key\") {\n\t\t// base64 blob invalid: ask user to re-export the key\n\t}\n}","preventionTips":["Use `ssh-keygen -y -f id_rsa` to produce a canonical pub key line","Avoid copy/paste through tools that wrap lines or normalize whitespace","Don't substitute PEM body base64 for the OpenSSH wire blob"],"tags":["ssh","base64","key-parsing"],"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-12T07:17:12.445Z"}