passbolt/passbolt_api · error · CustomValidationException

The OpenPGP key can not be used to encrypt.

Error message

The OpenPGP key can not be used to encrypt.

What it means

When the experimental config passbolt.gpg.experimental.encryptValidate is enabled, the server tries to actually encrypt to the submitted public key; if the encryption check fails a CustomValidationException is thrown. This guards against keys the backend GnuPG cannot use, which would otherwise only surface as login failures later.

Solutions

  1. Verify the key's creation date is not in the future (fix server clock or regenerate the key)
  2. Regenerate the key with a GnuPG-supported algorithm (e.g. RSA-3072/4096 or modern ECC) and retry
  3. Test locally that GnuPG can encrypt to the key: gpg --import key.asc && echo test | gpg --encrypt -r <fingerprint>
  4. Set Configure::read('passbolt.gpg.experimental.encryptValidate') to false in config to skip this experimental check (with the known trade-off)

Example fix

// config/passbolt.php
// before
'gpg' => ['experimental' => ['encryptValidate' => true]],
// after (only if accepting the risk of unusable keys)
'gpg' => ['experimental' => ['encryptValidate' => false]],
Defensive patterns

Strategy: validation

Validate before calling

// pre-check the key can encrypt (same check the server runs)
use App\Service\OpenPGP\PublicKeyCanEncryptCheckService;
$ok = PublicKeyCanEncryptCheckService::check($armoredKey, $fingerprint);

Try / catch

try {
    $user = $setupCompleteService->complete($userId);
} catch (\App\Error\Exception\CustomValidationException $e) {
    $msg = $e->getErrors()['gpgkey']['armored_key'] ?? $e->getMessage();
}

Prevention

When it happens

Trigger: Setup complete call with passbolt.gpg.experimental.encryptValidate=true and a key GnuPG cannot encrypt to: key creation date in the future, unsupported/weak algorithm, corrupted key packet, or fingerprint mismatch.

Common situations: Server clock skew making imported keys appear created in the future; keys generated with algorithms disabled in the server's GnuPG/gnupg homedir; old system keys after GnuPG upgrade.

Understand the failure class

Background: "Invalid value" and "allowed values are" config errors: what your library rejected and how to fix it — this error's family across 41 libraries.

Related errors


AI-assisted analysis of passbolt/passbolt_api@31c1bbc10f (2026-09-17). Data as JSON: /api/errors/46a756d42c81d6e3. Report an issue: GitHub.

Appendix: source

Thrown at src/Service/Setup/SetupCompleteService.php:97

        PublicKeyValidationService::parseAndValidatePublicKey(
            $gpgkey->armored_key,
            PublicKeyValidationService::getStrictRules()
        );

        // Check business rules before saving
        $this->Gpgkeys->checkRules($gpgkey);
        if ($gpgkey->getErrors()) {
            throw new ValidationException(__('The OpenPGP key data is not valid.'), $gpgkey, $this->Gpgkeys);
        }

        // Check key can be used to encrypt
        // This can happen for example if the key is created in the future
        // or some other issue prevent the backend to use it, we don't want to fail at the login step
        if (Configure::read('passbolt.gpg.experimental.encryptValidate')) {
            if (!PublicKeyCanEncryptCheckService::check($gpgkey->armored_key, $gpgkey->fingerprint)) {
                $msg = __('The OpenPGP key can not be used to encrypt.');
                Log::debug($msg, [$gpgkey->armored_key]);
                throw new CustomValidationException($msg, ['gpgkey' => ['armored_key' => $msg]]);
            }
        }

        // Consume atomically before the user save so a losing concurrent request never reaches persistence.
        $this->consumeTokenOrFail($token);

        $user->active = true;
        $user->gpgkey = $gpgkey;

        return $user;
    }

    /**
     * Saves and performs some checks on the user and its association
     *
     * @param \App\Model\Entity\User $user User to save
     * @param array|null $saveOptions options
     * @return \App\Model\Entity\User

View on GitHub (pinned to 31c1bbc10f)