passbolt/passbolt_api · error · ValidationException
The OpenPGP key data is not valid.
Error message
The OpenPGP key data is not valid.
What it means
During setup/recover completion, the submitted OpenPGP public key passed syntax parsing but failed the Gpgkeys table business rules (checkRules), so a ValidationException is thrown carrying the entity errors. Passbolt throws this to prevent persisting a key that would break encryption for the account.
Solutions
- Regenerate the key with GnuPG (modern algo, not expired/revoked) and retry setup with the fresh armored key
- Inspect the `errors` payload of the 400 response to see the exact failing Gpgkeys field
- Ensure the armored key corresponds to the fingerprint recorded when the registration token was issued
- Check the key has a single key block, valid user ID, and no future/invalid creation date
Example fix
// before: posting a mismatched key during setup
{ "gpgkey": { "armored_key": "-----BEGIN PGP PUBLIC KEY BLOCK----- ...other-identity-key..." } }
// after: use the key pair generated for this account
{ "gpgkey": { "armored_key": "-----BEGIN PGP PUBLIC KEY BLOCK----- ...account-key..." } } Defensive patterns
Strategy: validation
Validate before calling
use App\Service\OpenPGP\PublicKeyValidationService; PublicKeyValidationService::parseAndValidatePublicKey($armoredKey, PublicKeyValidationService::getStrictRules());
Try / catch
try {
$user = $setupCompleteService->complete($userId);
} catch (\App\Error\Exception\ValidationException $e) {
$fieldErrors = $e->getErrors(); // inspect gpgkey field errors
} Prevention
- Generate keys with standard GnuPG defaults (modern algorithms)
- Never edit or truncate armored key blocks
- Ensure the submitted key matches the fingerprint registered with the invite
- Test the key locally imports cleanly into gpg before submitting
When it happens
Trigger: POST to /setup/complete (or /recover/complete) with an armored key that violates model rules: invalid fingerprint checksum, mismatched key info versus armored key, duplicate fingerprint already registered, or missing/invalid key fields.
Common situations: User imports a different key than the one whose fingerprint is registered; key generated by non-compliant tooling; duplicate setup attempt with an already-stored key; truncated or edited armored key blocks.
Understand the failure class
Background: Schema validation failed / invalid input schema: payload rejected because its shape doesn't match the expected schema — this error's family across 28 libraries.
Related errors
- A valid OpenPGP key must be provided.
- A valid OpenPGP key must be provided.
- An OpenPGP key must be provided.
- Could not save the account recovery private key.
- Could not validate key revocation.
AI-assisted analysis of passbolt/passbolt_api@31c1bbc10f (2026-09-17).
Data as JSON: /api/errors/aca5df79a95b7f5d.
Report an issue: GitHub.
Appendix: source
Thrown at src/Service/Setup/SetupCompleteService.php:87
{
// Check request sanity
$user = $this->getAndAssertUser($userId);
$token = $this->getAndAssertToken($userId, AuthenticationToken::TYPE_REGISTER);
$gpgkey = $this->getAndAssertGpgkey($userId);
// New with 3.6 - Check armored key content
// The key must not be expired or revoked, or have multiple key blocks, etc.
// TODO w4.0 - Move to getAndAssertGpgkey
// Will break compat on recover for non compliant keys
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;View on GitHub (pinned to 31c1bbc10f)