passbolt/passbolt_api · error · CustomValidationException
Could not validate key revocation.
Error message
Could not validate key revocation.
What it means
Wrapper error thrown by buildRevokedKeyEntityFromDataOrFail when a ValidationException/CustomValidationException occurs while validating the revoked organization key — either the original active key lookup (findActiveKeyByFingerprintOrFail) or PublicKeyValidationService::parseAndValidatePublicKey with the revoked-key rules fails. Errors are nested under 'account_recovery_organization_revoked_key'.
Solutions
- Inspect errors.account_recovery_organization_revoked_key for the nested rule failure
- Ensure the armored_key is a proper revocation certificate generated with `gpg --gen-revoke <fingerprint>` (armored)
- Ensure the fingerprint matches the currently active organization recovery key
- Validate locally that the certificate parses: `gpg --import --import-options show-only <revoke.asc>`
Example fix
// before
{"armored_key": "<normal public key>", "fingerprint": "<fp>"}
// after
gpg --armor --gen-revoke <fp> > revoke.asc
{"armored_key": "<contents of revoke.asc>", "fingerprint": "<fp>"} Defensive patterns
Strategy: validation
Validate before calling
// A revocation cert looks like a public key block; ensure it parses and matches the active fp
if (!armored_key.includes('-----BEGIN PGP PUBLIC KEY BLOCK-----')) {
throw new Error('Provide an armored revocation certificate');
}
if (fingerprint !== activeOrgKeyFingerprint) {
throw new Error('Fingerprint must match the active organization key');
} Type guard
function isRevocationPayloadForActiveKey(p, activeFp) {
return typeof p.armored_key === 'string'
&& p.armored_key.includes('BEGIN PGP PUBLIC KEY BLOCK')
&& p.fingerprint === activeFp;
} Try / catch
try {
await api.disableOrganizationPolicy(revocationPayload);
} catch (e) {
const nested = e.body?.errors?.account_recovery_organization_revoked_key;
console.error(nested); // shows which rule (or key lookup) failed
} Prevention
- Generate revocation certificates at key-creation time and store them safely
- Ensure the fingerprint matches the currently active organization key
- Verify the certificate locally with gpg show-only import options
When it happens
Trigger: Calling set() or disablePolicy() (policy disable flow) where the submitted revocation certificate's armored_key fails revoked-key validation rules, or the fingerprint doesn't correspond to an active organization key.
Common situations: Admin submits the current public key instead of a revocation certificate; revocation key has a fingerprint matching no active key; malformed or truncated revocation armor during policy disable.
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
- Could not save the account recovery private key.
- Could not validate policy data.
- Could not validate public key data.
- The OpenPGP key can not be used to encrypt.
- A valid OpenPGP key must be provided.
AI-assisted analysis of passbolt/passbolt_api@31c1bbc10f (2026-09-17).
Data as JSON: /api/errors/8109688de2082bf4.
Report an issue: GitHub.
Appendix: source
Thrown at plugins/PassboltEe/AccountRecovery/src/Service/AccountRecoveryOrganizationPolicies/AbstractAccountRecoveryOrganizationPolicySetService.php:310
* Check user provided valid valid account_recovery_organization_revoked_key
* Return patched entity corresponding to the key to revoke (e.g. to update in DB)
*
* @param \App\Utility\UserAccessControl $uac user access control
* @throws \App\Error\Exception\CustomValidationException if any of the check on fingerprint or armored key data fails
* @return \Passbolt\AccountRecovery\Model\Entity\AccountRecoveryOrganizationPublicKey currently in use key patched with new revoked armored_key
*/
public function buildRevokedKeyEntityFromDataOrFail(UserAccessControl $uac): AccountRecoveryOrganizationPublicKey
{
try {
$data = $this->getData('account_recovery_organization_revoked_key');
$entity = $this->AccountRecoveryOrganizationPublicKeys->buildAndValidateEntity($uac, $data);
$oldEntity = $this->findActiveKeyByFingerprintOrFail($entity->fingerprint);
PublicKeyValidationService::parseAndValidatePublicKey(
$entity->armored_key,
PublicKeyValidationService::getRevokedKeyRules()
);
} catch (ValidationException | CustomValidationException $exception) {
throw new CustomValidationException(__('Could not validate key revocation.'), [
'account_recovery_organization_revoked_key' => $exception->getErrors(),
]);
} catch (Exception $exception) {
throw new CustomValidationException(__('Could not validate key revocation.'), [
'account_recovery_organization_revoked_key' => [
'armored_key' => [
'invalidArmoredKey' => $exception->getMessage(),
],
],
]);
}
// Check revocation cryptographically
// parseAndValidatePublicKey only do superficial signature check
if (!(new PublicKeyRevocationCheckService())->check($entity->armored_key)) {
throw new CustomValidationException(__('Could not validate key revocation.'), [
'account_recovery_organization_revoked_key' => __('Could not validate key revocation.'),
]);View on GitHub (pinned to 31c1bbc10f)