passbolt/passbolt_api · error · App\Error\Exception\CustomValidationException
The user cannot be deleted.
Error message
The user cannot be deleted.
What it means
Before deleting, the controller runs CakePHP's delete rules on the user (checkRules with RulesChecker::DELETE). If any business rule fails — typically the user is sole manager of a non-empty group, or sole owner of shared resources (and folders when the plugin is enabled) — a CustomValidationException is thrown with a body enumerating the blocking groups/resources/folders. The deletion is refused so shared content does not become orphaned.
Solutions
- Read the exception body: it lists sole-managed groups and solely-owned resources/folders
- Transfer group management: POST /groups/<id> with owners/managers changes including the new owners
- Transfer resource/folder ownership: PUT /share/<resourceId> or folder share endpoint adding another owner
- Retry the delete once all transfers are done; use the dry-run (?dry-run=true) to re-check first
Example fix
// before
deleteUser(userId); // 422: The user cannot be deleted.
// after
await shareResource(resourceId, { aro: newOwnerId, type: 15 }); // OWNER
await editGroup(groupId, { owners: [newManagerId] });
deleteUser(userId); Defensive patterns
Strategy: try-catch
Validate before calling
const dry = await api.deleteUser(id, { dryRun: true });
if (dry.blockingGroups?.length || dry.blockingResources?.length) await transferOwnership(dry); Try / catch
try { await api.deleteUser(id); } catch (e) { if (e.status === 422 && e.body?.errors) { await handleTransfer(e.body.errors); return retryDelete(id); } throw e; } Prevention
- Always run the dry-run first and inspect the returned blocking entities
- Transfer group management and resource/folder ownership before offboarding deletes
- Never leave a user as sole owner of shared content in onboarding policies
When it happens
Trigger: DELETE /users/<id> where the target user is the only group manager of a group with other members, or the only owner of shared resources/folders, without first transferring ownership; the response body lists the offending entities under errors.groups/errors.resources/errors.folders.
Common situations: Offboarding an employee who created all the team passwords; deleting a user who administrates shared groups; running the delete dry-run and then calling delete without handling the transfer payload.
Understand the failure class
Background: Schema validation failed / invalid input schema: payload rejected because its shape doesn't match the expected schema — this error's family across 28 libraries.
Related errors
- Could not validate user data.
- The user with username
- group(s) returned by your directory are invalid and will be…
- " " is not a valid contain value.
- " " is not a valid datetime for filter .
AI-assisted analysis of passbolt/passbolt_api@31c1bbc10f (2026-09-17).
Data as JSON: /api/errors/b5ea2f94a4eef43a.
Report an issue: GitHub.
Appendix: source
Thrown at src/Controller/Users/UsersDeleteController.php:259
$foldersTable = TableRegistry::getTableLocator()->get('Passbolt/Folders.Folders');
$folders = $foldersTable->findIndex($user->id, $findFoldersOptions);
$body['errors']['folders']['sole_owner'] = $folders;
$msg .= ' ' . $errors['id']['soleOwnerOfSharedContent'];
}
}
}
$groupsToDeleteIds = $this->GroupsUsers
->findGroupsWhereUserOnlyMember($user->id)
->all()
->extract('group_id')
->toArray();
if ($groupsToDeleteIds) {
$groupsToDelete = $this->Groups->findAllByIds($groupsToDeleteIds);
$body['groups_to_delete'] = $groupsToDelete;
}
throw new CustomValidationException($msg, $body);
}
}
/**
* Transfer the group managers which blocked the user delete
*
* @param \App\Model\Entity\User $user entity
* @throws \Cake\Http\Exception\BadRequestException The groups that required a change are not all satisfied
* @return void
*/
protected function _transferGroupsManagers(User $user)
{
$managers = $this->request->getData('transfer.managers');
if (empty($managers)) {
return;
}
$groupsUsersIdsToUpdate = Hash::extract($managers, '{n}.id');View on GitHub (pinned to 31c1bbc10f)