passbolt/passbolt_api · error · BadRequestException
Account recovery is disabled. Key backup is not supported.
Error message
Account recovery is disabled. Key backup is not supported.
What it means
Thrown in AccountRecoverySetupCompleteService::assertRequestSanity when the organization account recovery policy is 'disabled' yet the client still sends account recovery user setting data (e.g. a recovery preference) in the setup complete payload. With recovery disabled, key backup is unsupported, so any recovery-related payload is rejected as a bad request.
Solutions
- Remove the account recovery user setting data from the setup complete request payload and retry
- Reload the setup page so the client fetches the current organization recovery policy and hides backup options
- If backup should be available, re-enable the account recovery policy in the admin settings (with correct EE license)
- Clear browser cache / update the passbolt web extension to the version matching the server policy
Example fix
// before
payload = { ...baseData, account_recovery_user_setting: 'enabled' };
// after (policy disabled)
payload = { ...baseData }; // no recovery fields when policy is disabled Defensive patterns
Strategy: validation
Validate before calling
const policy = await getOrgPolicy();
if (policy === 'disabled' && 'account_recovery_user_setting' in payload) {
delete payload.account_recovery_user_setting;
} Type guard
const recoveryDataProvided = (p) => p != null && ('account_recovery_user_setting' in p || 'account_recovery_private_key' in p); Try / catch
try {
await setupComplete(payload);
} catch (e) {
if (e.code === 400 && /disabled/.test(e.message)) {
payload = stripRecoveryFields(payload);
await setupComplete(payload);
} else { throw e; }
} Prevention
- Refresh the organization recovery policy before rendering the setup UI
- Keep browser extension and server versions in sync
- Strip recovery fields from payloads when policy is 'disabled'
- Reload the page after admin changes to recovery settings
When it happens
Trigger: POST /setup/setup/complete (or account recovery setup complete) where the org policy is disabled and the request body contains account_recovery_user_setting (or related recovery fields).
Common situations: Organization administrator disabled account recovery after the client UI was loaded (stale UI still offers 'save my key on server'); a cached/stale front-end bundle posting legacy recovery fields; misconfigured environment where the EE account recovery setting was toggled off mid-setup.
Understand the failure class
Background: Conflicting config options: "cannot be used together" — configuration validation errors across open-source libraries — this error's family across 162 libraries.
Related errors
- Account recovery is mandatory. Please provide the mandatory…
- Could not save the account recovery setting.
- Invalid request. You cannot opt-out.
- The account recovery is mandatory and cannot be rejected.
- The account recovery request status is not approved.
AI-assisted analysis of passbolt/passbolt_api@31c1bbc10f (2026-09-17).
Data as JSON: /api/errors/7b4c4298aca053bc.
Report an issue: GitHub.
Appendix: source
Thrown at plugins/PassboltEe/AccountRecovery/src/Service/Setup/AccountRecoverySetupCompleteService.php:130
return $this->saveUserEntity($user, $saveOptions);
}
);
}
/**
* Assert that there is not too much or not enough data
* Mandatory: both private key and password must be provided
* Disabled: none of them must be provided
*
* @return void
* @throws \Cake\Http\Exception\BadRequestException if data is missing or too much data is sent
*/
protected function assertRequestSanity(): void
{
if ($this->policy->isDisabled()) {
if ($this->isAccountRecoveryUserSettingProvided()) {
throw new BadRequestException(__('Account recovery is disabled. Key backup is not supported.'));
}
} elseif ($this->policy->isMandatory()) {
if (!$this->isPrivateKeyProvided() || !$this->arePasswordsProvided()) {
throw new BadRequestException(
__('Account recovery is mandatory. Please provide the mandatory data.')
);
}
}
}
/**
* @return bool true if the account_recovery_user_setting data is set
*/
protected function isAccountRecoveryUserSettingProvided(): bool
{
return is_array($this->request->getData('account_recovery_user_setting'));
}
View on GitHub (pinned to 31c1bbc10f)