passbolt/passbolt_api · critical · InternalErrorException
Could not delete the user
Error message
Could not delete the user {0}, please try again later. What it means
Thrown by UsersTable::softDelete() when persisting 'deleted = true' on the user entity fails via save() with checkRules disabled. The user is not removed logically, and the API returns a 500. Because validation is bypassed, the failure indicates a database or persistence-layer problem rather than bad input.
Solutions
- Retry the deletion after confirming the database is reachable and no locks exist on the users row.
- Inspect error logs for the underlying SQL exception to identify the root cause.
- Verify users table integrity and disk space; ensure writes are not hitting a read-only replica.
- If the failure happened after partial cleanup (associated data may already be deleted), reconcile state manually or re-run the deletion flow.
Example fix
// caller before
catch (InternalErrorException $e) { /* swallow */ }
// after
catch (InternalErrorException $e) {
// check DB health, then retry user deletion with backoff
} Defensive patterns
Strategy: retry
Validate before calling
if (!$this->Users->exists(['id' => $userId, 'deleted' => false])) { return; } Type guard
if (!Cake\Validation\Validation::uuid($userId)) { throw new InvalidArgumentException('Invalid user id.'); } Try / catch
try { $this->Users->softDelete($user); } catch (\Cake\Http\Exception\InternalErrorException $e) { // inspect DB, retry with backoff or reconcile state } Prevention
- Avoid concurrent edits of the same user row.
- Monitor DB locks and connectivity.
- Make deletion flows idempotent and retryable.
- Log the underlying save() failure cause.
When it happens
Trigger: DELETE /users/{id}.json (user deletion flow) or direct softDelete() call when the UPDATE on the users row fails — connection drop, row lock/timeout, trigger/constraint rejection, or DB read-only state.
Common situations: Concurrent operations locking the users row (e.g. an active session update); MySQL lock wait timeout; DB failover; disk-full; GPG/auth token side-tables with blocking triggers in customized installs.
Related errors
- Could not delete the group
- Could not save the user, try again later.
- The user metadata private keys could not be deleted.
- The user metadata session keys could not be deleted.
- 500
AI-assisted analysis of passbolt/passbolt_api@31c1bbc10f (2026-09-17).
Data as JSON: /api/errors/fda79973cb8e2a31.
Report an issue: GitHub.
Appendix: source
Thrown at src/Model/Table/UsersTable.php:562
'foreign_key' => $user->id,
'foreign_model' => ScimEntry::FOREIGN_MODEL_USERS,
]);
}
// Delete all tags
if (Configure::read('passbolt.plugins.tags.enabled')) {
$ResourcesTags = TableRegistry::getTableLocator()->get('Passbolt/Tags.ResourcesTags');
$ResourcesTags->deleteAll(['user_id' => $user->id]);
/** @var \Passbolt\Tags\Model\Table\TagsTable $Tags */
$Tags = TableRegistry::getTableLocator()->get('Passbolt/Tags.Tags');
$Tags->deleteAllUnusedTags();
}
// Mark user as deleted
$user->deleted = true;
if (!$this->save($user, ['checkRules' => false])) {
$msg = __('Could not delete the user {0}, please try again later.', $user->username);
throw new InternalErrorException($msg);
}
return $entitiesChanges;
}
/**
* Register a user
*
* @param array $data register data
* @param \App\Utility\UserAccessControl|null $control who is requesting the registration
* @throws \Cake\Http\Exception\InternalErrorException if there was an issue during the save
* @throws \App\Error\Exception\ValidationException if the user data do not validate
* @return \App\Model\Entity\User entity
*/
public function register(array $data, ?UserAccessControl $control = null): User
{
// if role id is empty make it a user
// Only admins are allowed to set the roleView on GitHub (pinned to 31c1bbc10f)