getsops/sops · error

github.com/ProtonMail/go-crypto/openpgp error: %w

Error message

github.com/ProtonMail/go-crypto/openpgp error: %w

What it means

EncryptContext tries key.encryptWithOpenPGP (github.com/ProtonMail/go-crypto/openpgp) first; if it fails and OpenPGP is not disabled, the error is appended as 'github.com/ProtonMail/go-crypto/openpgp error: %w'. This is one of two attempts collected before the aggregate failure; it means the pure-Go OpenPGP path could not encrypt the data key to the key's fingerprint (missing key in keyring, unreadable pubring, malformed key, etc.).

Source

Thrown at pgp/keysource.go:284

// fingerprint as the MasterKey.
//
// Consider using EncryptContext instead.
func (key *MasterKey) Encrypt(dataKey []byte) error {
	return key.EncryptContext(context.Background(), dataKey)
}

// EncryptContext encrypts the data key with the PGP key with the same
// fingerprint as the MasterKey.
func (key *MasterKey) EncryptContext(ctx context.Context, dataKey []byte) error {
	var errs errSet

	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()

View on GitHub (pinned to 13442bb981)

Solutions

  1. Import the recipient public key: gpg --import <pubkey-file> (into the GNUPGHOME sops uses)
  2. Export to a legacy-format keyring readable by go-crypto, or set SOPS_GPG_EXEC and rely on the gpg-binary fallback
  3. Verify the fingerprint matches an existing key: gpg --list-keys <fingerprint>
  4. If you intend to use only the gpg binary, ensure the binary path is valid so the fallback succeeds

Example fix

// before
sops -e file.yaml  # fails: fingerprint not in keyring
// after
gpg --import teammate.pub.asc && sops -e file.yaml
Defensive patterns

Strategy: validation

Validate before calling

fp := strings.ReplaceAll(fingerprint, " ", "")
out, err := exec.Command("gpg", "--homedir", gnupgHome, "--list-keys", fp).CombinedOutput()
if err != nil || !strings.Contains(string(out), fp) {
    return fmt.Errorf("public key %s not present; run gpg --import first: %s", fp, out)
}

Try / catch

if err := key.EncryptContext(ctx, dataKey); err != nil {
    var agg interface{ Unwrap() []error }
    if errors.As(err, &agg) || strings.Contains(err.Error(), "go-crypto/openpgp error") {
        log.Warn("OpenPGP path failed; check keyring or rely on gpg fallback")
    }
    return err
}

Prevention

When it happens

Trigger: Calling EncryptContext when the public keyring (pubRing or default pubring.gpg in the GnuPG home) cannot be read/parsed, or does not contain a usable public key for key.Fingerprint.

Common situations: Fingerprint in .sops.yaml never imported into the local keyring; GnuPG 2.1+ kbx format that go-crypto cannot read; GNUPGHOME pointing at an empty temp dir; expired/revoked recipient key.

Related errors


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