invoke-ai/InvokeAI · error · LastAdministratorError

LAST_ADMIN_DETAIL

Error message

LAST_ADMIN_DETAIL

What it means

_assert_not_last_admin raises LastAdministratorError(LAST_ADMIN_DETAIL) ('Cannot remove the last administrator') when an update or delete would demote, deactivate, or remove the only remaining active admin. The guard counts active admins inside the same write-locked transaction as the write, so it is race-safe. The system user is also protected separately via _assert_system_user_protected.

Source

Thrown at invokeai/app/services/users/users_default.py:409

        being ``None``, which would also describe a rename. Only a change that actually
        revokes administrator status is checked, so renaming the last admin stays allowed.
        """
        cursor.execute("SELECT is_admin, is_active FROM users WHERE user_id = ?", (user_id,))
        row = cursor.fetchone()
        if row is None:
            return

        # An admin who is already inactive is not counted, so removing them changes nothing.
        if not (bool(row[0]) and bool(row[1])):
            return

        if not (is_deleting or is_admin is False or is_active is False):
            return

        cursor.execute("SELECT COUNT(*) FROM users WHERE is_admin = TRUE AND is_active = TRUE")
        count_row = cursor.fetchone()
        if (int(count_row[0]) if count_row else 0) <= 1:
            raise LastAdministratorError(LAST_ADMIN_DETAIL)

    def _assert_system_user_protected(
        self,
        user_id: str,
        *,
        is_deleting: bool = False,
        is_admin: bool | None = None,
        is_active: bool | None = None,
        password: str | None = None,
    ) -> None:
        """Reject changes to the ``system`` account that no legitimate operation needs.

        The system row owns every board, image, workflow, and queue item carried over from
        before multiuser support. Deleting or deactivating it strands all of that: queued
        items are rejected at dequeue and media reads and saves raise ``PermissionError``.

        Promotion and password-setting are refused for a different reason. The system row
        is active but has an empty password hash, so it can never authenticate — yet

View on GitHub (pinned to 0b6a024f2f)

Solutions

  1. Promote a second active admin first (update another user with is_admin=True), then demote/delete the original.
  2. Modify a different field instead: renaming the last admin or changing their password is explicitly allowed; only is_admin=False, is_active=False, or delete trigger the guard.
  3. Catch LastAdministratorError at the call site and surface the policy message to the end user rather than treating it as a bug.
  4. For self-service flows, disable the 'demote/deactivate/delete' affordance in the UI when COUNT(active admins) <= 1.

Example fix

// before
users.update(last_admin_id, UserUpdateRequest(is_admin=False))  # LastAdministratorError
// after
users.update(other_user_id, UserUpdateRequest(is_admin=True))   # ensure a successor
users.update(last_admin_id, UserUpdateRequest(is_admin=False))
Defensive patterns

Strategy: try-catch

Validate before calling

row = db.run_sql('SELECT COUNT(*) FROM users WHERE is_admin = TRUE AND is_active = TRUE').fetchone()
active_admins = int(row[0]) if row else 0
if active_admins <= 1 and (changes.is_admin is False or changes.is_active is False):
    raise PolicyError('Promote another admin before demoting the last one')

Try / catch

from invokeai.app.services.users.users_common import LastAdministratorError
try:
    users.update(user_id, changes)
except LastAdministratorError:
    flash('Cannot remove the last administrator; promote another admin first')
except ValueError as e:
    raise

Prevention

When it happens

Trigger: update(user_id, UserUpdateRequest(is_admin=False)) or (is_active=False) on the sole active admin; delete(user_id) on the sole active admin; demoting/deactivating the last of two admins after the other was already removed.

Common situations: Admin UIs letting the sole admin demote themselves; cleanup scripts bulk-deactivating users without checking admin counts; fixture teardown deleting the seeded admin before other tests need an admin; concurrent operations that legitimately emptied the admin pool just before your call.

Related errors


AI-assisted analysis of invoke-ai/InvokeAI@0b6a024f2f (2026-08-29). Data as JSON: /api/errors/9d06930acf633916. Report an issue: GitHub.