passbolt/passbolt_api · error · Exception
User could not be updated.
Error message
User could not be updated.
What it means
This generic Exception is thrown by UserSyncAction::updateUser when the Users table save() call returns false but the entity carries no validation errors, so the sync action cannot report a precise cause. It is a last-resort fallback in the LDAP directory-sync user-update flow: the persistence layer failed for a reason outside field validation (e.g. database error, event listener aborting the save). Because the message carries no entity or SQL detail, debugging requires inspecting server logs.
Solutions
- Check passbolt error logs (logs/error.log) for the underlying database or event-listener error at the time of the sync run.
- Re-run the sync with debug enabled or inspect $user->getErrors() and the save() return path in UserSyncAction to identify why save() failed without validation errors.
- Verify the users table schema matches migrations: run `ddev refresh` / `passbolt migrate` to ensure no stale constraints.
- Disable third-party plugins hooking into Users model events to rule out a listener aborting the save, then re-run sync.
Example fix
// before: silent fallback hides the cause
throw new Exception('User could not be updated.');
// after: surface the underlying save failure
$err = $this->Users->getConnection()->errorInfo ?? null;
throw new Exception('User could not be updated. Save failed' . ($err ? ': ' . json_encode($err) : '.') . ' User id: ' . $existingUser->id); Defensive patterns
Strategy: try-catch
Validate before calling
if (!$user->getErrors() && !$this->Users->save($user)) {
error_log('User save failed for id ' . $existingUser->id . ' errors: ' . json_encode($user->getErrors()));
} Try / catch
try {
$syncService->updateUser($user, $entry);
} catch (ValidationException $e) {
// entity-level issues
} catch (Exception $e) {
if ($e->getMessage() === 'User could not be updated.') {
// inspect server logs / retry save manually to find root cause
}
} Prevention
- Validate user data with the Users table validator before attempting the sync save.
- Keep model event listeners (plugins) tested so they never abort save() without setting errors.
- Keep migrations up to date so no stale DB constraints fail saves silently.
- Monitor logs/error.log during sync runs.
When it happens
Trigger: Running `passbolt directory_sync` sync where an existing user matched from the LDAP directory has changed attributes (e.g. full name) and $this->Users->save($user) returns false with $user->hasErrors() === false. Typical concrete causes: a beforeSave/afterSave rule failing silently, a database constraint violation, or a model event listener calling stopPropagation/aborting the save without setting entity errors.
Common situations: AD/LDAP sync updating a user whose data passes entity validation but breaks at the database level (e.g. NULL in a non-null column introduced by a plugin hook); corrupted users table row; custom plugin event listeners on Model.beforeSave that block saves; MySQL/Postgres constraint mismatch after a partial migration.
Related errors
- group(s) returned by your directory are invalid and will be…
- users returned by your directory are invalid and will be…
- An error has occurred parsing groupCustomFilter
- An error has occurred parsing userCustomFilter
- Could not validate directory entry data.
AI-assisted analysis of passbolt/passbolt_api@31c1bbc10f (2026-09-17).
Data as JSON: /api/errors/4114c83c3edefa55.
Report an issue: GitHub.
Appendix: source
Thrown at plugins/PassboltEe/DirectorySync/src/Actions/UserSyncAction.php:144
/**
* Update user
*
* @param \App\Model\Entity\User $existingUser User
* @param array $data data
* @return void
*/
private function updateUser(User $existingUser, array $data): void
{
try {
$user = $this->Users->editEntity($existingUser, $data, new UserAccessControl(Role::ADMIN));
$result = $this->Users->save($user, ['checkrules' => false]);
if (!$result) {
if ($user->hasErrors()) {
$msg = __('Could not validate user data.');
throw new ValidationException($msg, $user, $this->Users);
}
throw new Exception('User could not be updated.');
}
// Send report.
$this->addReportItem(new ActionReport(
__(
'The user {0} full name has been successfully updated to {1} {2}.',
$existingUser->username,
$user->profile->first_name,
$user->profile->last_name
),
Alias::MODEL_USERS,
Alias::ACTION_UPDATE,
Alias::STATUS_SUCCESS,
$user
));
} catch (Exception $exception) {
$error = new SyncError($existingUser, $exception);
$this->addReportItem(new ActionReport(
__(View on GitHub (pinned to 31c1bbc10f)