getsops/sops · error
failed to encrypt sops data key with pgp: %s
Error message
failed to encrypt sops data key with pgp: %s
What it means
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.
Source
Thrown at pgp/keysource.go:357
// PGP key that belongs to Fingerprint. It sets EncryptedDataKey, or returns
// an error.
func (key *MasterKey) encryptWithGnuPG(ctx context.Context, dataKey []byte) error {
fingerprint := shortenFingerprint(key.Fingerprint)
args := []string{
"--no-default-recipient",
"--yes",
"--encrypt",
"-a",
"-r",
key.Fingerprint,
"--trusted-key",
fingerprint,
"--no-encrypt-to",
}
stdout, stderr, err := gpgExec(ctx, key.gnuPGHomeDir, args, bytes.NewReader(dataKey))
if err != nil {
return fmt.Errorf("failed to encrypt sops data key with pgp: %s", strings.TrimSpace(stderr.String()))
}
key.SetEncryptedDataKey(bytes.TrimSpace(stdout.Bytes()))
return nil
}
// EncryptIfNeeded encrypts the data key with PGP only if it's needed,
// that is, if it hasn't been encrypted already.
func (key *MasterKey) EncryptIfNeeded(dataKey []byte) error {
if key.EncryptedKey == "" {
return key.Encrypt(dataKey)
}
return nil
}
// EncryptedDataKey returns the encrypted data key this master key holds.
func (key *MasterKey) EncryptedDataKey() []byte {
return []byte(key.EncryptedKey)View on GitHub (pinned to 13442bb981)
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
Example fix
// before sops -e file.yaml # failed to encrypt sops data key with pgp: gpg: No public key // after gpg --recv-keys <fingerprint> && sops -e file.yaml
Defensive patterns
Strategy: try-catch
Validate before calling
if out, err := exec.Command("gpg", "--homedir", gnupgHome, "--list-keys", fingerprint).CombinedOutput(); err != nil {
return fmt.Errorf("recipient %s missing from keyring: %s", fingerprint, out)
} Try / catch
if err := encrypt(...); err != nil {
var gpgErr *fmt.Errorf
if errors.As(err, &gpgErr) && strings.Contains(err.Error(), "failed to encrypt sops data key with pgp") {
// err text contains gpg's trimmed stderr; log it verbatim for diagnosis
log.Errorf("gpg encrypt failed: %v", err)
}
return err
} Prevention
- 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
When it happens
Trigger: 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.
Common situations: 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.
Related errors
- GnuPG binary error: %w
- github.com/ProtonMail/go-crypto/openpgp error: %w
- could not encrypt data key with PGP key: %w
- Could not initialize AES GCM encryption cipher: %s
- Could not generate random bytes for IV: %s
AI-assisted analysis of getsops/sops@13442bb981 (2026-09-01).
Data as JSON: /api/errors/ea6b21dcad8716f1.
Report an issue: GitHub.