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
- Read the `errors` in the 400 response for the exact violated rule.
- Move users off the role (reassign) before deleting it.
- Do not attempt to delete built-in/system roles (admin, user) — these are protected.
- 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
- Never attempt to delete built-in roles (admin, user, guest)
- Reassign users off the role before deleting
- Check the RolesTable rules to know which roles are protected
- Read the per-field `errors` in the 400 response
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
- The role could not be saved.
- The role could not be updated.
- The role does not exist or deleted.
- The role does not exist or deleted.
- The role identifier is not valid.
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)