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
- Verify the key's creation date is not in the future (fix server clock or regenerate the key)
- Regenerate the key with a GnuPG-supported algorithm (e.g. RSA-3072/4096 or modern ECC) and retry
- Test locally that GnuPG can encrypt to the key: gpg --import key.asc && echo test | gpg --encrypt -r <fingerprint>
- 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
- Keep server clock synchronized (NTP) so future-dated keys are detected
- Avoid exotic/deprecated key algorithms not supported by server GnuPG
- Verify with `gpg --encrypt -r <fingerprint>` locally before submission
- Know that encryptValidate is experimental; treat its failures as key-quality signals
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
- Could not use the key to encrypt.
- The metadata could not be encrypted with the user id: .
- The OpenPGP server key defined in the config cannot be used…
- This is not a valid setting.
- A value for the theme should be provided.
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\UserView on GitHub (pinned to 31c1bbc10f)