passbolt/passbolt_api · error · App\Error\Exception\CustomValidationException
Could not validate password data.
Error message
Could not validate password data.
What it means
Thrown by AccountRecoveryPrivateKeyPasswordsValidationService::buildPasswordEntitiesFromDataOrFail after it builds password entities and rule-checks them: any entity whose errors() are non-empty (business rules or message composition failures) is collected, and if any errors exist a CustomValidationException is raised with the per-index entity errors under 'account_recovery_private_key_passwords'.
Solutions
- Inspect the per-index errors returned in the exception details under account_recovery_private_key_passwords and fix the flagged field(s)
- Verify each 'data' value is a valid OpenPGP message encrypted for the recipient user's account-recovery key
- Confirm every recipient user_id exists, is active, and has completed account-recovery setup (has a private key to receive the share)
- Retry entries one at a time to isolate the failing row before fixing the batch
Example fix
// before
{"user_id": "unknown-uuid", "data": "plaintext-secret"}
// after
{"user_id": "<existing-active-user-uuid>", "data": "<openpgp-message-encrypted-for-user-recovery-key>"} Defensive patterns
Strategy: validation
Validate before calling
// Validate each entry before building entities:
foreach ($passwordsData as $i => $entry) {
if (empty($entry['user_id']) || !Uuid::isValid($entry['user_id'])) {
throw new \InvalidArgumentException("Entry {$i}: invalid user_id");
}
if (empty($entry['data']) || !str_starts_with($entry['data'], '-----BEGIN PGP MESSAGE-----')) {
throw new \InvalidArgumentException("Entry {$i}: data must be an armored OpenPGP message");
}
} Type guard
$isValidEntry = fn(array $e): bool =>
isset($e['user_id'], $e['data'], $e['private_key_id'])
&& Uuid::isValid($e['user_id']) && Uuid::isValid($e['private_key_id'])
&& is_string($e['data']) && $e['data'] !== ''; Try / catch
try {
$entities = $validationService->buildPasswordEntitiesFromDataOrFail($uac, $data);
} catch (\App\Error\Exception\CustomValidationException $e) {
$perIndexErrors = $e->getErrors()['account_recovery_private_key_passwords'];
foreach ($perIndexErrors as $i => $errs) {
// log/fix the specific fields failing on row $i
}
} Prevention
- Encrypt each password share with the recipient user's account-recovery public key, never plaintext
- Confirm recipients completed account-recovery setup before including them in the payload
- Fix one row at a time; the exception reports errors per index, so isolate the bad entry
- Keep the OpenPGP library and key formats up to date to avoid message-composition rule failures
When it happens
Trigger: Creating/updating account recovery private key passwords where an entry fails entity-level rules — invalid user_id (recipient not found/not active), missing or malformed encrypted 'data', invalid private_key_id, or failed message composition (e.g. recipient has no configured account-recovery key).
Common situations: Passing plaintext instead of the expected encrypted message format; referencing a user who never completed account-recovery setup so their key/stamp is missing; schema/rounding issues in the base64 OpenPGP message payload; bulk payload where one bad row aborts the whole batch.
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
- The OpenPGP armored key could not be validated.
- A valid OpenPGP key must be provided.
- A valid OpenPGP key must be provided.
- Could not save the account recovery private key.
- Could not validate folder data.
AI-assisted analysis of passbolt/passbolt_api@31c1bbc10f (2026-09-17).
Data as JSON: /api/errors/c945574ab8ca0c7c.
Report an issue: GitHub.
Appendix: source
Thrown at plugins/PassboltEe/AccountRecovery/src/Service/AccountRecoveryPrivateKeyPasswords/AccountRecoveryPrivateKeyPasswordsValidationService.php:102
$errors[$i]['recipient_fingerprint']['wrongRecipient'] = $msg;
continue;
}
// Check subkey id in message packet
if (!MessageRecipientValidationService::isMessageForRecipient($msgInfo, $keyInfo)) {
$errors[$i]['data']['wrongRecipient'] = $msg;
continue;
}
// Check business rules
if (!$this->AccountRecoveryPrivateKeyPasswords->checkRules($entity)) {
$errors[$i] = $entity->getErrors();
}
}
// Throw an error on business rules or message composition
if (count($errors)) {
throw new CustomValidationException(__('Could not validate password data.'), [
'account_recovery_private_key_passwords' => $errors,
]);
}
return $passwordEntities;
}
}
View on GitHub (pinned to 31c1bbc10f)