passbolt/passbolt_api · critical · InternalErrorException
Could not save the user, try again later.
Error message
Could not save the user, try again later.
What it means
Thrown by UsersTable::register() when save($user, ['checkRules' => false]) returns false despite the entity passing validation and rules — a database write failure. InternalErrorException results, so the caller gets a 500 and the user record was not created (though the DB may need state reconciliation if side effects already ran).
Solutions
- Retry the registration once the database is healthy; if it was a unique-key race, handle the duplicate-username case explicitly.
- Check application and DB error logs for the underlying SQL exception.
- Verify DB connectivity, write permissions, and disk space.
- Add a unique index on users.username at DB level and catch duplicate-key errors to return a clean 400 instead of 500.
Example fix
// caller before
catch (InternalErrorException $e) { /* generic 500 */ }
// after
catch (InternalErrorException $e) {
// check DB health / duplicate-key race, then retry or return 400
} Defensive patterns
Strategy: retry
Validate before calling
if (!$this->Users->exists(['username' => $data['username']]) && $this->Users->getConnection()->isConnected()) { /* safe to attempt save */ } Try / catch
try { $user = $this->Users->register($data); } catch (\Cake\Http\Exception\InternalErrorException $e) { // check DB health / duplicate-key race; retry or map to 409 } Prevention
- Enforce a DB unique index on users.username.
- Serialize registrations for the same email.
- Monitor DB health and disk space.
- Catch duplicate-key SQL errors and translate to clean 4xx responses.
When it happens
Trigger: Registration flow (POST /users.json or self-registration) when the INSERT into users fails: connection loss, duplicate key race between checkRules and save, lock timeout, read-only DB, or trigger rejecting the insert.
Common situations: Two concurrent registrations with the same email racing past the isUnique check into a DB unique constraint failure; DB failover during registration; disk-full server; customized installs with failing triggers on users insert.
Related errors
- Could not delete the user
- 500
- Could not create the folder, please try again later.
- Could not create the resource folder relation, please try…
- Could not delete the draft SSO settings.
AI-assisted analysis of passbolt/passbolt_api@31c1bbc10f (2026-09-17).
Data as JSON: /api/errors/441ceb68260caa1d.
Report an issue: GitHub.
Appendix: source
Thrown at src/Model/Table/UsersTable.php:604
// which causes isUnique build rule not to work when looking for duplicate entries.
$data['deleted'] = false;
// Check validation rules
$user = $this->buildEntity($data);
if ($user->getErrors()) {
throw new ValidationException(__('Could not validate user data.'), $user, $this);
}
// Check business rules
$this->checkRules($user);
if ($user->getErrors()) {
throw new ValidationException(__('Could not validate user data.'), $user, $this);
}
// Check for internal error on save
$user = $this->save($user, ['checkRules' => false]);
if (!$user) {
throw new InternalErrorException('Could not save the user, try again later.');
}
// Generate an authentication token
/** @var \App\Model\Table\AuthenticationTokensTable $AuthenticationTokens */
$AuthenticationTokens = TableRegistry::getTableLocator()->get('AuthenticationTokens');
$token = $AuthenticationTokens->generate($user->id, AuthenticationToken::TYPE_REGISTER);
// Generate event data
$eventData = ['user' => $user, 'token' => $token];
if ($control && $control->getId()) {
$eventData['adminId'] = $control->getId();
/** @psalm-suppress InvalidArgument */
$this->dispatchEvent(static::AFTER_REGISTER_SUCCESS_EVENT_NAME, $eventData, $this);
} else {
/** @psalm-suppress InvalidArgument */
$this->dispatchEvent(self::AFTER_SELF_REGISTER_SUCCESS_EVENT_NAME, $eventData, $this);
}
View on GitHub (pinned to 31c1bbc10f)