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

  1. Retry the registration once the database is healthy; if it was a unique-key race, handle the duplicate-username case explicitly.
  2. Check application and DB error logs for the underlying SQL exception.
  3. Verify DB connectivity, write permissions, and disk space.
  4. 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

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


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)