passbolt/passbolt_api · error · ValidationException

Could not save the account recovery private key.

Error message

Could not save the account recovery private key.

What it means

Thrown when the account_recovery_private_key association attached to the user entity fails validation while saving during account recovery setup completion. The private key to be escrowed is malformed (e.g. not a valid OpenPGP key message) or violates entity rules, and the ValidationException exposes the errors plus the AccountRecoveryPrivateKeys table.

Solutions

  1. Check the errors object in the ValidationException response to identify the failing key field
  2. Verify the private key is armored, complete, and encrypted for the organization recovery key before sending
  3. Ensure the key is generated/encrypted with a supported OpenPGP implementation (GnuPG/OpenPGP.js as used by the extension)
  4. Regenerate the recovery data by restarting the setup flow with a current browser extension version

Example fix

// before
keyPayload = { data: rawPrivateKeyString }; // unencrypted/invalid
// after
keyPayload = { data: await encryptForOrgRecoveryKey(privateKeyArmored) };
Defensive patterns

Strategy: try-catch

Validate before calling

if (!/-----BEGIN PGP MESSAGE-----/.test(payload.account_recovery_private_key?.data ?? '')) {
  throw new Error('Recovery private key must be an armored encrypted message');
}

Type guard

const isValidRecoveryKey = (k) => k != null && typeof k.data === 'string' && k.data.startsWith('-----BEGIN PGP MESSAGE-----');

Try / catch

try {
  await setupComplete(payload);
} catch (e) {
  if (e.name === 'ValidationException' && e.errors?.account_recovery_private_key) {
    restartKeyEncryptionStep();
  } else { throw e; }
}

Prevention

When it happens

Trigger: POST setup complete where the provided account recovery private key entity has validation errors — invalid armored key, missing required fields (data, user_id), or key not decryptable/associated correctly.

Common situations: Client encrypts the recovery key with the wrong organization key; corrupted or truncated armored key in the payload; custom integrations posting raw keys instead of the expected structure; key generated by an unsupported OpenPGP implementation.

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


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

Appendix: source

Thrown at plugins/PassboltEe/AccountRecovery/src/Service/Setup/AccountRecoverySetupCompleteService.php:188

     * @param \App\Model\Entity\User $user User entity
     * @param array|null $saveOptions options
     * @return \App\Model\Entity\User
     */
    protected function saveUserEntity(User $user, ?array $saveOptions = []): User
    {
        $user = parent::saveUserEntity($user, $saveOptions);

        if ($this->isAccountRecoveryUserSettingProvided()) {
            if ($user->get('account_recovery_user_setting')->hasErrors()) {
                throw new ValidationException(
                    'Could not save the account recovery setting.',
                    $user->get('account_recovery_user_setting'),
                    $this->AccountRecoveryUserSettings
                );
            }

            if ($user->hasValue('account_recovery_private_key') && $user->get('account_recovery_private_key')->hasErrors()) { // phpcs:ignore
                throw new ValidationException(
                    'Could not save the account recovery private key.',
                    $user->get('account_recovery_private_key'),
                    $this->AccountRecoveryPrivateKeys
                );
            }
        }

        return $user;
    }
}

View on GitHub (pinned to 31c1bbc10f)