passbolt/passbolt_api · error · Cake\Http\Exception\BadRequestException
Invalid request. Passwords are required for this change.
Error message
Invalid request. Passwords are required for this change.
What it means
This BadRequestException is thrown during an organization key rotation when existing user backups (account_recovery_private_key_passwords rows) are present in the database, but the request does not include the re-encrypted private key passwords. Because the organization private key changes, all stored backups must be re-encrypted against the new key and re-submitted, otherwise existing users would lose recovery capability.
Solutions
- Before rotating, ensure every user with a backup re-encrypts their private key password data against the new organization public key and include it in 'account_recovery_private_key_passwords'.
- If no backups should exist, verify and clear stale rows first — the check triggers only when backupsExists() is true.
- Include the full set of passwords (count must match stored backups; see assertPasswordsCount) encrypted with the new key.
- Use the official passbolt key-rotation workflow/UI which collects re-encrypted passwords from users before applying rotation.
Example fix
// before (rotation without re-encrypted backups)
await passbolt.rotateAccountRecoveryKey({
account_recovery_organization_public_key: newArmoredKey,
account_recovery_organization_revoked_key: oldArmoredKey
});
// after (rotation including re-encrypted passwords)
await passbolt.rotateAccountRecoveryKey({
account_recovery_organization_public_key: newArmoredKey,
account_recovery_organization_revoked_key: oldArmoredKey,
account_recovery_private_key_passwords: reencryptedPasswords
}); Defensive patterns
Strategy: validation
Validate before calling
const current = await passbolt.getAccountRecoveryOrganizationPolicy();
const hasBackups = current.backupsCount > 0; // or check via API
if (hasBackups && !payload.account_recovery_private_key_passwords?.length) {
throw new Error('Existing backups detected: include re-encrypted account_recovery_private_key_passwords with the rotation.');
} Try / catch
try {
await passbolt.rotateAccountRecoveryKey(payload);
} catch (e) {
if (e.status === 400 && /Passwords are required for this change/.test(e.message)) {
// start the user-facing flow to collect re-encrypted passwords, then retry
return startReencryptionFlow();
}
throw e;
} Prevention
- Before rotating, query the server for existing backups and plan the re-encryption collection workflow.
- Never rotate the organization key on instances with users' backups without completing the re-encryption step.
- Remember the password count must exactly match stored backups (assertPasswordsCount).
When it happens
Trigger: Key rotation request (new public key + revoked key provided) where backupsExists() finds stored private key password backups, but 'account_recovery_private_key_passwords' is absent from the payload. Raised in AccountRecoveryOrganizationPolicySetService::set() at line 109.
Common situations: An admin rotates the organization recovery key without first collecting and re-encrypting all users' backup passwords; a script automates rotation assuming an empty backups table; a client version predating the backups-required rule; testing on a instance where backups were created after the payload was built.
Understand the failure class
Background: "missing required argument" and "the following required arguments were not provided": what required-argument errors mean and how to fix them — this error's family across 20 libraries.
Related errors
- Invalid request. Keys are required for this change.
- Invalid request. New key is required for key rotation.
- Invalid request. New key or passwords are not required.
- Invalid request. Revoked key is required for key rotation.
- Account recovery case must be a string.
AI-assisted analysis of passbolt/passbolt_api@31c1bbc10f (2026-09-17).
Data as JSON: /api/errors/37136fc53397e311.
Report an issue: GitHub.
Appendix: source
Thrown at plugins/PassboltEe/AccountRecovery/src/Service/AccountRecoveryOrganizationPolicies/AccountRecoveryOrganizationPolicySetService.php:109
if (($isNewKeyProvided && !$isRevokedKeyProvided) || (!$isNewKeyProvided && $isRevokedKeyProvided)) {
throw new BadRequestException(__('Invalid request. Keys are required for this change.'));
}
// if key provided or revocation provided
$newKey = null;
$oldKey = null;
$passwords = null;
/** @psalm-suppress RedundantCondition */
if ($isNewKeyProvided && $isRevokedKeyProvided) {
// assert old and new key$newKey
$newKey = $this->buildPublicKeyEntityFromDataOrFail($uac);
$oldKey = $this->buildRevokedKeyEntityFromDataOrFail($uac);
// If some existing backups are present
// assert new backups are provided
if ($this->backupsExists()) {
if (!$isPrivateKeyPasswordsProvided) {
throw new BadRequestException(__('Invalid request. Passwords are required for this change.'));
}
// assert passwords backups format and numbers
$passwords = $this->buildPasswordEntitiesFromDataOrFail($uac, $newKey);
}
$newPolicy->account_recovery_organization_public_key = $newKey;
} else {
// If key is not changing reuse the old one
if (!isset($newPolicy->public_key_id)) {
throw new CustomValidationException(__('Could not validate public key data.'), [
'public_key_id' => [
'_required' => __('An organization public key is required.'),
],
]);
} else {
if ($newPolicy->public_key_id !== $this->getCurrentPolicyEntity()->public_key_id) {
throw new CustomValidationException(__('Could not validate public key data.'), [
'public_key_id' => [
'notCurrentPublicKeyId' => __('The public_key_id must match current policy public_key_id.'),View on GitHub (pinned to 31c1bbc10f)