passbolt/passbolt_api · error · Cake\Http\Exception\BadRequestException

The account recovery is mandatory and cannot be rejected.

Error message

The account recovery is mandatory and cannot be rejected.

What it means

Thrown by validateStatusAgainstOrganizationPolicy() when the organization recovery policy is 'mandatory' but the user attempts to set their status to 'rejected'. The organization setting takes precedence over individual choice, so rejection is a bad request.

Solutions

  1. Check the organization policy first and send status=approved when mandatory
  2. Update clients to hide the opt-out option when policy is mandatory
  3. If opt-out must be allowed, have an admin change the organization policy away from mandatory

Example fix

// before
$service->set(['status' => 'rejected']);
// after
$policy = (new AccountRecoveryOrganizationPolicyGetService())->getOrFail();
$status = $policy->isMandatory() ? 'approved' : $desiredStatus;
$service->set(['status' => $status]);
Defensive patterns

Strategy: validation

Validate before calling

const policy = await getOrgPolicy(); if (policy.isMandatory && desiredStatus === 'rejected') desiredStatus = 'approved';

Type guard

const allowedStatus = (policy, s) => policy.isMandatory ? (s === 'approved' ? s : null) : s;

Try / catch

try { await setSettings(data); } catch (e) { if (e.status === 400 && /mandatory/.test(e.message)) { /* force approved */ } }

Prevention

When it happens

Trigger: Saving account recovery user settings with status=rejected (or opt-out) while AccountRecoveryOrganizationPolicy is set to mandatory; a client sending a default opt-out payload without checking org policy.

Common situations: Organization admins switched policy to mandatory while users still run old clients that attempt opt-out; automated scripts copying settings between orgs with different policies.

Understand the failure class

Background: UnsupportedOperationException and "is not supported" errors: when a library deliberately refuses a call — this error's family across 30 libraries.

Related errors


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

Appendix: source

Thrown at plugins/PassboltEe/AccountRecovery/src/Service/AccountRecoveryUserSettings/AccountRecoveryUserSettingsSetService.php:136

            $passwords = $this->buildPasswordEntitiesFromDataOrFail();
            $key->set('account_recovery_private_key_passwords', $passwords);
            $setting->set('account_recovery_private_key', $key);
        }

        $this->validateStatusAgainstOrganizationPolicy($setting);

        return $setting;
    }

    /**
     * @param \Passbolt\AccountRecovery\Model\Entity\AccountRecoveryUserSetting $setting Setting to validate
     * @return void
     * @throws \Cake\Http\Exception\BadRequestException if the status is rejected but the organisation setting to mandatory
     */
    protected function validateStatusAgainstOrganizationPolicy(AccountRecoveryUserSetting $setting): void
    {
        if ($this->organizationPolicy->isMandatory() && $setting->isRejected()) {
            throw new BadRequestException(__('The account recovery is mandatory and cannot be rejected.'));
        }
    }

    /**
     * @param string $status Status
     * @throws \App\Error\Exception\CustomValidationException if the settings does not validate
     * @return \Passbolt\AccountRecovery\Model\Entity\AccountRecoveryUserSetting
     */
    protected function validateAccountRecoveryUserSetting(string $status): AccountRecoveryUserSetting
    {
        try {
            return $this->AccountRecoveryUserSettings->buildAndValidateEntity($this->uac, $status);
        } catch (ValidationException $exception) {
            throw new CustomValidationException($exception->getMessage(), [
                'account_recovery_user_setting' => $exception->getErrors(),
            ]);
        }
    }

View on GitHub (pinned to 31c1bbc10f)