{"record":{"id":"4f125ff915acb07b","repo":"getsops/sops","slug":"failed-to-parse-input-as-age-ssh-public-key-w","errorCode":null,"errorMessage":"failed to parse input as age-ssh public key: %w","messagePattern":"failed to parse input as age-ssh public key: %w","errorType":"error_code","errorClass":null,"httpStatus":null,"severity":"error","filePath":"age/keysource.go","lineNumber":514,"sourceCode":"\n\t\treturn parsedRecipient, nil\n\tcase strings.HasPrefix(recipient, \"age1\") && strings.Count(recipient, \"1\") > 1:\n\t\tparsedRecipient, err := plugin.NewRecipient(recipient, pluginTerminalUI)\n\t\tif err != nil {\n\t\t\treturn nil, fmt.Errorf(\"failed to parse input as age key from age plugin: %w\", err)\n\t\t}\n\t\treturn parsedRecipient, nil\n\tcase strings.HasPrefix(recipient, \"age1\"):\n\t\tparsedRecipient, err := age.ParseX25519Recipient(recipient)\n\t\tif err != nil {\n\t\t\treturn nil, fmt.Errorf(\"failed to parse input as Bech32-encoded age public key: %w\", err)\n\t\t}\n\n\t\treturn parsedRecipient, nil\n\tcase strings.HasPrefix(recipient, \"ssh-\"):\n\t\tparsedRecipient, err := agessh.ParseRecipient(recipient)\n\t\tif err != nil {\n\t\t\treturn nil, fmt.Errorf(\"failed to parse input as age-ssh public key: %w\", err)\n\t\t}\n\t\treturn parsedRecipient, nil\n\t}\n\n\treturn nil, fmt.Errorf(\"failed to parse input, unknown recipient type: %q\", recipient)\n}\n\n// parseIdentities attempts to parse one or more age identities from the provided reader.\n// One identity per line.\n// Empty lines and lines starting with \"#\" are ignored.\n// If allowMultipleKeysPerLine is true, every non-empty lines is split by words,\n// and every word is parsed as an identity.\nfunc parseIdentities(r io.Reader, allowMultipleKeysPerLine bool) (ParsedIdentities, error) {\n\tvar identities ParsedIdentities\n\n\tscanner := bufio.NewScanner(r)\n\n\tfor scanner.Scan() {","sourceCodeStart":496,"sourceCodeEnd":532,"githubUrl":"https://github.com/getsops/sops/blob/13442bb98183887d7a9ac09ec8ab0564673a59d8/age/keysource.go#L496-L532","documentation":"The recipient had an ssh- prefix so sops parsed it as an SSH public key via agessh.ParseRecipient; the key is not a supported SSH key type or the string is malformed (e.g. an ssh-ed25519 or rsa key is supported, but certain key formats/curves or a truncated/garbled key fail). This is the age-ssh branch of parseRecipient, used when encrypting sops files to SSH keys.","triggerScenarios":"parseRecipient receives a recipient starting with ssh-; agessh.ParseRecipient fails because the key body is corrupt, base64 decoding fails, or the SSH key type is unsupported (e.g. some certificate or exotic curve formats).","commonSituations":"Pasting a private SSH key instead of the .pub; truncated authorized_keys line; unsupported SSH key algorithm (e.g. sk-ed25519 security keys in older age versions, or DSA keys which age rejects); certificate files (ssh-keygen -CA-issued certs) rather than raw public keys.","solutions":["Use the contents of the .pub file (single line, starts with ssh-ed25519/ssh-rsa/ecdsa-sha2-...) and paste it fully, one key per recipient entry.","Confirm the key type is supported by agessh: ed25519, rsa, ecdsa p256/p384/p521; regenerate with ssh-keygen -t ed25519 if using DSA/exotic types.","Check for missing 'comment' handling isn't the issue — the first two fields must be intact; avoid mangling via shell word-splitting (quote the key).","If using hardware-backed sk- keys, verify age/sops version supports them or use the vendor's age plugin instead.","Run `ssh-keygen -lf mykey.pub` to confirm the file is a valid public key before adding to .sops.yaml."],"exampleFix":"# before (.sops.yaml)\nkeys:\n  - ssh-ed25519 AAAAC3Nza   # truncated\n// failed to parse input as age-ssh public key: ...\n\n# after\ncat ~/.ssh/id_ed25519.pub\n# ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAI... user@host\nkeys:\n  - ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAI...full-key... user@host","handlingStrategy":"validation","validationCode":"// shell: verify the SSH key is a supported public key before adding to .sops.yaml\nhead -n1 mykey.pub | awk '{print $1}' | grep -Eq '^(ssh-ed25519|ssh-rsa|ecdsa-sha2-nistp(256|384|521))$' \\\n  || { echo \"unsupported or malformed ssh key type\"; exit 1; }\nssh-keygen -lf mykey.pub >/dev/null || { echo \"invalid public key\"; exit 1; }","typeGuard":null,"tryCatchPattern":"rk, err := sopsage.MasterKeyFromRecipient(recipient)\nif err != nil && strings.Contains(err.Error(), \"age-ssh public key\") {\n    return fmt.Errorf(\"unsupported/malformed SSH key %q: use ssh-ed25519/rsa/ecdsa .pub content: %w\", recipient, err)\n}","preventionTips":["Only paste .pub file contents — never private keys or certificates.","Prefer ed25519 SSH keys; regenerate unsupported types (DSA, sk- in old age).","Quote SSH keys when passing through shells to avoid field truncation.","Validate with ssh-keygen -lf before adding to .sops.yaml.","One key per keys entry in .sops.yaml; no merged authorized_keys blobs."],"tags":["age","ssh","recipient","parsing"],"backgroundTag":"invalid-age-recipient","analyzedSha":"13442bb98183887d7a9ac09ec8ab0564673a59d8","analyzedAt":"2026-09-01T03:53:00.447Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}