getsops/sops · error

could not encrypt data key with PGP key: %w

Error message

could not encrypt data key with PGP key: %w

What it means

This is the aggregate error returned by EncryptContext after both the go-crypto OpenPGP attempt and the gpg-binary fallback failed. It wraps a multi-error list containing the openpgp error and the 'GnuPG binary error'. Seeing it means sops could not encrypt the data key to this PGP master key by any available method.

Source

Thrown at pgp/keysource.go:295

	if !key.disableOpenPGP {
		openpgpErr := key.encryptWithOpenPGP(dataKey)
		if openpgpErr == nil {
			log.WithField("fingerprint", key.Fingerprint).Info("Encryption succeeded")
			return nil
		}
		errs = append(errs, fmt.Errorf("github.com/ProtonMail/go-crypto/openpgp error: %w", openpgpErr))
	}

	binaryErr := key.encryptWithGnuPG(ctx, dataKey)
	if binaryErr == nil {
		log.WithField("fingerprint", key.Fingerprint).Info("Encryption succeeded")
		return nil
	}
	errs = append(errs, fmt.Errorf("GnuPG binary error: %w", binaryErr))

	log.WithField("fingerprint", key.Fingerprint).Info("Encryption failed")
	return fmt.Errorf("could not encrypt data key with PGP key: %w", errs)
}

// encryptWithOpenPGP attempts to encrypt the data key using OpenPGP with the
// PGP key that belongs to Fingerprint. It sets EncryptedDataKey, or returns
// an error.
func (key *MasterKey) encryptWithOpenPGP(dataKey []byte) error {
	entity, err := key.retrievePubKey()
	if err != nil {
		return err
	}

	encBuf := new(bytes.Buffer)
	armorBuf, err := armor.Encode(encBuf, "PGP MESSAGE", nil)
	if err != nil {
		return err
	}
	plainBuf, err := openpgp.Encrypt(armorBuf, []*openpgp.Entity{&entity}, nil, &openpgp.FileHints{IsBinary: true}, nil)
	if err != nil {

View on GitHub (pinned to 13442bb981)

Solutions

  1. Read both wrapped causes and fix the more specific one (usually 'No public key')
  2. Import the public key for the fingerprint and verify with gpg --list-keys <fingerprint>
  3. Confirm the fingerprint in .sops.yaml matches a real key (no typos, no spaces issues)
  4. Ensure a working gpg binary exists (or SOPS_GPG_EXEC points to it) and GNUPGHOME is valid (0700 dir)

Example fix

// before
pgp: 'C6A0...BEEF'  # key never imported
// after
gpg --import team-keys.asc && gpg --list-keys C6A0...BEEF  # then re-run sops -e
Defensive patterns

Strategy: try-catch

Validate before calling

fp := fingerprint
for _, args := range [][]string{
    {"--homedir", gnupgHome, "--list-keys", fp},
    {"--homedir", gnupgHome, "--list-secret-keys", fp},
} {
    if out, err := exec.Command("gpg", args...).CombinedOutput(); err != nil {
        return fmt.Errorf("key %s unavailable (%v): %s", fp, err, out)
    }
}

Try / catch

if err := key.EncryptContext(ctx, dataKey); err != nil {
    var errs []error
    if errors.As(err, &errs) { // aggregate wraps both openpgp and gpg errors
        for _, e := range errs { log.Errorf("pgp encrypt: %v", e) }
    }
    return fmt.Errorf("encrypt to %s failed; run 'gpg --import' and retry: %w", key.Fingerprint, err)
}

Prevention

When it happens

Trigger: Calling EncryptContext (directly or via sops encrypt) when the fingerprint is unknown to both the Go keyring and the gpg binary, or both mechanisms fail (bad GNUPGHOME, missing gpg, unusable key).

Common situations: Fresh machine/CI container without imported keys; typo'ed fingerprint in .sops.yaml; gpg not installed; empty injected GnuPGHome.

Related errors


AI-assisted analysis of getsops/sops@13442bb981 (2026-09-01). Data as JSON: /api/errors/128611111a0dcb28. Report an issue: GitHub.