passbolt/passbolt_api · error · CustomValidationException

The role could not be deleted.

Error message

The role could not be deleted.

What it means

RolesDeleteService::softDeleteRole throws this CustomValidationException when saving the soft-delete flag fails model validation/rules (PersistenceFailedException), instead of an actual delete. Field-level errors are attached to the response.

Solutions

  1. Read the `errors` in the 400 response for the exact violated rule.
  2. Move users off the role (reassign) before deleting it.
  3. Do not attempt to delete built-in/system roles (admin, user) — these are protected.
  4. Check RolesTable rules (src/Model/Table/RolesTable.php) for isDeletable-style rules.

Example fix

// before
DELETE /roles/<role-still-assigned> -> 400 The role could not be deleted
// after
# reassign users to another role first, then
DELETE /roles/<empty-role-id> -> 200
Defensive patterns

Strategy: try-catch

Validate before calling

const roles = await api.listRoles();
const role = roles.find(r => r.id === roleId);
if (!role) throw new Error('Role not found');
if (['admin', 'user', 'guest'].includes(role.name)) {
  throw new Error('Built-in roles cannot be deleted');
}

Type guard

function isDeletableRole(role) {
  return role && typeof role.id === 'string' && !['admin', 'user', 'guest'].includes(role.name);
}

Try / catch

try {
  await api.deleteRole(roleId);
} catch (e) {
  if (e.status === 400 && e.body?.errors) {
    // rule violation: reassign users or unprotect built-in role, then retry
  } else throw e;
}

Prevention

When it happens

Trigger: DELETE /roles/{id} where marking the role deleted violates a Roles table rule — e.g. a rulesChecker preventing deletion of a role still assigned to users or of the admin role.

Common situations: Attempting to delete built-in roles (admin, user, guest) that a rule protects, deleting a role that still has users associated, or concurrent modifications tripping optimistic-locking checks.

Related errors


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

Appendix: source

Thrown at src/Service/Roles/RolesDeleteService.php:100

     */
    private function softDeleteRole(Role $role, UserAccessControl $uac): Role
    {
        $data = [
            'deleted' => DateTime::now(),
            'deleted_by' => $uac->getId(),
        ];

        $role = $this->Roles->patchEntity($role, $data, ['accessibleFields' => [
            'deleted' => true,
            'deleted_by' => true,
        ]]);

        try {
            $result = $this->Roles->saveOrFail($role);
        } catch (PersistenceFailedException $e) { // @phpstan-ignore-line
            $errors = $e->getEntity()->getErrors();

            throw new CustomValidationException(
                __('The role could not be deleted.'),
                $errors
            );
        } catch (Exception $e) {
            throw new InternalErrorException(__('Could not delete the role, please try again later.'), null, $e);
        }

        return $result;
    }
}

View on GitHub (pinned to 31c1bbc10f)