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

Invalid request. No policy change.

Error message

Invalid request. No policy change.

What it means

Thrown by `set` when the request is a no-op: the policy value does not change AND neither a new public key nor a revoked key is provided. Passbolt rejects requests that would leave the organization recovery configuration untouched because there is nothing to persist.

Solutions

  1. Only call the endpoint when the policy actually changes or a key rotation/revocation is intended
  2. Include a new public key or a revoked key if you intend to rotate keys while keeping the same policy
  3. Check the current policy via GET first and skip the update if identical

Example fix

// before
await api.put('/account-recovery/organization-settings.json', { policy: 'opt-in' }); // already opt-in
// after
if (currentPolicy !== 'opt-in') {
  await api.put('/account-recovery/organization-settings.json', { policy: 'opt-in' });
}
Defensive patterns

Strategy: validation

Validate before calling

if (currentPolicy === desiredPolicy && !newKey && !revokedKey) return; // skip no-op update

Prevention

When it happens

Trigger: PUT /account-recovery/organization-settings.json with the same policy value currently stored and no `armored_key`/`new_key`/`revoked_key` fields in the payload.

Common situations: Frontend submits the settings form without changes; automation re-applies the same desired state; client omitted the new-key field by mistake while intending a rotation.

Understand the failure class

Background: "Must be a positive integer", "Invalid value", "Unsupported": the invalid-argument-value error family, when a library rejects the value you pass — this error's family across 35 libraries.

Related errors


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

Appendix: source

Thrown at plugins/PassboltEe/AccountRecovery/src/Service/AccountRecoveryOrganizationPolicies/AccountRecoveryOrganizationPolicySetService.php:53

     * @param array $data user provided data
     * @return \Passbolt\AccountRecovery\Model\Entity\AccountRecoveryOrganizationPolicy
     */
    public function set(UserAccessControl $uac, array $data): AccountRecoveryOrganizationPolicy
    {
        $this->setData($data);

        // assert policy is provided as it should in any case
        $newPolicy = $this->buildAndValidatePolicyEntityFromData($uac);

        // Check request composition to understand user goal
        $isPolicyChange = $this->isPolicyChange();
        $isNewKeyProvided = $this->isPublicKeyProvided();
        $isRevokedKeyProvided = $this->isRevokedKeyProvided();
        $isPrivateKeyPasswordsProvided = $this->isPrivateKeyPasswordsProvided();

        // if policy has not changed and (new key not provided or revoked key not provided)
        if (!$isPolicyChange && !$isNewKeyProvided && !$isRevokedKeyProvided) {
            throw new BadRequestException(__('Invalid request. No policy change.'));
        }
        if (!$isPolicyChange && $isNewKeyProvided && !$isRevokedKeyProvided) {
            throw new BadRequestException(__('Invalid request. Revoked key is required for key rotation.'));
        }
        /** @psalm-suppress RedundantCondition */
        if (!$isPolicyChange && !$isNewKeyProvided && $isRevokedKeyProvided) {
            throw new BadRequestException(__('Invalid request. New key is required for key rotation.'));
        }

        // if disabled => enabled
        if ($this->isEnabling()) {
            // if public key is not provided
            if (!$isNewKeyProvided) {
                throw new BadRequestException(__('Invalid request. An organization recovery public key is required.'));
            }
            // if key revocation or passwords provided
            if ($isRevokedKeyProvided || $isPrivateKeyPasswordsProvided) {
                throw new BadRequestException(__('Invalid request. Revoked key or passwords are not required.'));

View on GitHub (pinned to 31c1bbc10f)