{"record":{"id":"ea6b21dcad8716f1","repo":"getsops/sops","slug":"failed-to-encrypt-sops-data-key-with-pgp-s","errorCode":null,"errorMessage":"failed to encrypt sops data key with pgp: %s","messagePattern":"failed to encrypt sops data key with pgp: (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"pgp/keysource.go","lineNumber":357,"sourceCode":"// PGP key that belongs to Fingerprint. It sets EncryptedDataKey, or returns\n// an error.\nfunc (key *MasterKey) encryptWithGnuPG(ctx context.Context, dataKey []byte) error {\n\tfingerprint := shortenFingerprint(key.Fingerprint)\n\n\targs := []string{\n\t\t\"--no-default-recipient\",\n\t\t\"--yes\",\n\t\t\"--encrypt\",\n\t\t\"-a\",\n\t\t\"-r\",\n\t\tkey.Fingerprint,\n\t\t\"--trusted-key\",\n\t\tfingerprint,\n\t\t\"--no-encrypt-to\",\n\t}\n\tstdout, stderr, err := gpgExec(ctx, key.gnuPGHomeDir, args, bytes.NewReader(dataKey))\n\tif err != nil {\n\t\treturn fmt.Errorf(\"failed to encrypt sops data key with pgp: %s\", strings.TrimSpace(stderr.String()))\n\t}\n\n\tkey.SetEncryptedDataKey(bytes.TrimSpace(stdout.Bytes()))\n\treturn nil\n}\n\n// EncryptIfNeeded encrypts the data key with PGP only if it's needed,\n// that is, if it hasn't been encrypted already.\nfunc (key *MasterKey) EncryptIfNeeded(dataKey []byte) error {\n\tif key.EncryptedKey == \"\" {\n\t\treturn key.Encrypt(dataKey)\n\t}\n\treturn nil\n}\n\n// EncryptedDataKey returns the encrypted data key this master key holds.\nfunc (key *MasterKey) EncryptedDataKey() []byte {\n\treturn []byte(key.EncryptedKey)","sourceCodeStart":339,"sourceCodeEnd":375,"githubUrl":"https://github.com/getsops/sops/blob/13442bb98183887d7a9ac09ec8ab0564673a59d8/pgp/keysource.go#L339-L375","documentation":"encryptWithGnuPG runs the gpg binary with --encrypt and --trusted-key; if gpg exits non-zero, this error is returned with gpg's trimmed stderr embedded. It identifies the exact failure output from the gpg process used to encrypt the sops data key. Notably it uses --no-encrypt-to and trusts the key explicitly, so most failures are key availability/usability problems.","triggerScenarios":"EncryptContext falls back to encryptWithGnuPG and gpg fails: key not in keyring ('No public key'), key expired/revoked, gpg binary missing, GNUPGHOME invalid, or agent/PIN issues.","commonSituations":"Recipient key never imported; running as a different user with another GNUPGHOME; expired key in .sops.yaml; gpg 2.x prompting in a non-interactive CI environment.","solutions":["Read the embedded stderr string for gpg's specific message","gpg --import the recipient public key and verify with gpg --list-keys <fingerprint>","Use --import-options show-only or set the key to ultimate trust if 'No public key'/'unusable pubkey' persists; replace expired keys","Confirm gpg is installed and SOPS_GPG_EXEC resolves correctly"],"exampleFix":"// before\nsops -e file.yaml  # failed to encrypt sops data key with pgp: gpg: No public key\n// after\ngpg --recv-keys <fingerprint> && sops -e file.yaml","handlingStrategy":"try-catch","validationCode":"if out, err := exec.Command(\"gpg\", \"--homedir\", gnupgHome, \"--list-keys\", fingerprint).CombinedOutput(); err != nil {\n    return fmt.Errorf(\"recipient %s missing from keyring: %s\", fingerprint, out)\n}","typeGuard":null,"tryCatchPattern":"if err := encrypt(...); err != nil {\n    var gpgErr *fmt.Errorf\n    if errors.As(err, &gpgErr) && strings.Contains(err.Error(), \"failed to encrypt sops data key with pgp\") {\n        // err text contains gpg's trimmed stderr; log it verbatim for diagnosis\n        log.Errorf(\"gpg encrypt failed: %v\", err)\n    }\n    return err\n}","preventionTips":["Read the embedded stderr — it names the exact gpg failure (No public key, expired, etc.)","gpg --import recipient keys before encrypting; verify with gpg --list-keys","Avoid running gpg as a different user than the key owner without GNUPGHOME set","Rotate expired keys and update .sops.yaml fingerprints"],"tags":["gnupg","gpg-binary","encryption","subprocess"],"backgroundTag":"gpg-command-failed","analyzedSha":"13442bb98183887d7a9ac09ec8ab0564673a59d8","analyzedAt":"2026-09-01T03:53:00.447Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}