passbolt/passbolt_api · error · InternalErrorException

Cleanup command cannot be executed on an instance having no…

Error message

Cleanup command cannot be executed on an instance having no active administrator.

What it means

The cleanup command (bin/cake passbolt cleanup) repairs referential integrity of the database (deleted users, missing keys, permissions). Before running it asserts the database state, and Check 2 requires at least one active administrator (UsersTable::findFirstAdmin() returns null). Passbolt throws InternalErrorException because performing cleanup on an instance with no active admin would leave the instance administratively unrecoverable.

Solutions

  1. Re-activate an administrator directly in the database: UPDATE users SET is_active = 1, is_deleted = 0 WHERE id = (SELECT id FROM users u JOIN roles r ON r.id = u.role_id WHERE r.name = 'admin' LIMIT 1);
  2. If no admin account exists at all, register one with 'bin/cake passbolt register_user -r admin -u you@example.com -f First -l Last' after ensuring the roles table contains 'admin'.
  3. Restore the deleted admin account via 'bin/cake passbolt restore_deleted_user <userId>' if it was soft-deleted.
  4. Re-run 'bin/cake passbolt cleanup' once an active admin exists.

Example fix

// SQL before (no active admin found)
SELECT * FROM users WHERE is_active = false;
-- after: reactivate the admin
UPDATE users SET is_active = true WHERE id = '<admin-uuid>';
$ bin/cake passbolt cleanup
Defensive patterns

Strategy: validation

Validate before calling

$adminCount = TableRegistry::getTableLocator()->get('Users')->find()
    ->innerJoinWith('Roles', fn($q) => $q->where(['Roles.name' => 'admin']))
    ->where(['Users.is_active' => true, 'Users.is_deleted' => false])
    ->count();
if ($adminCount === 0) { die("Recover/create an active admin before running cleanup.\n"); }

Try / catch

try {
    $this->CleanupCommand->execute(...);
} catch (InternalErrorException $e) {
    if (str_contains($e->getMessage(), 'no active administrator')) {
        // bootstrap an admin account first, then retry
    }
}

Prevention

When it happens

Trigger: Running 'bin/cake passbolt cleanup' when the users table has no user with role 'admin' and is_active=true (or is_deleted=false), so findFirstAdmin() returns null.

Common situations: All admins were soft-deleted or deactivated (e.g. offboarding every admin via UI/API); a data restore or migration dropped admin rows; the cleanup was run on a fresh/broken database before any admin user exists.

Understand the failure class

Background: EmptyResultError / "no results found": when an API or scraper succeeds but returns zero rows — this error's family across 9 libraries.

Related errors


AI-assisted analysis of passbolt/passbolt_api@31c1bbc10f (2026-09-17). Data as JSON: /api/errors/cd667e0236dfc70a. Report an issue: GitHub.

Appendix: source

Thrown at src/Command/CleanupCommand.php:229

     * @return void
     * @throws \Cake\Http\Exception\InternalErrorException If database is not in valid state.
     */
    private function assertDatabaseState(): void
    {
        // Check 1. Users table exist in db
        /** @var \Cake\Database\Connection $connection */
        $connection = ConnectionManager::get('default');
        $listTables = $connection->getSchemaCollection()->listTables();
        if (!in_array('users', $listTables)) {
            throw new InternalErrorException(
                __('Cleanup command cannot be executed on an instance having no users table.')
            );
        }

        // Check 2. Atleast one active administrator is present
        $admin = $this->Users->findFirstAdmin();
        if (is_null($admin)) {
            throw new InternalErrorException(
                __('Cleanup command cannot be executed on an instance having no active administrator.')
            );
        }
    }

    /**
     * Convert the method name to a human readeable string. eg. "cleanupMethodName" become "Method Name".
     *
     * @param string $methodName Method name
     * @return string
     */
    private function methodNameToCleanupName(string $methodName): string
    {
        // Remove the "cleanup" prefix if present
        $name = preg_replace('/^cleanup/i', '', $methodName);
        if ($name === '' || $name === null) {
            $name = $methodName;
        }

View on GitHub (pinned to 31c1bbc10f)