invoke-ai/InvokeAI · error · HTTPException
The system user cannot be deleted, deactivated, promoted to
Error message
The system user cannot be deleted, deactivated, promoted to administrator, or given a password
What it means
HTTP 400 raised by update_user when the request targets SYSTEM_USER_ID with is_active=false, is_admin=true, or a password (auth.py:587). The built-in system user owns all pre-multiuser content (boards, images, workflows, queue items), so deactivating it strands that content and promoting/giving it credentials is refused. SYSTEM_USER_PROTECTED_DETAIL is the friendly front for the `_assert_system_user_protected` service backstop.
Source
Thrown at invokeai/app/api/routers/auth.py:587
"""
user_service = ApiDependencies.invoker.services.users
config = ApiDependencies.invoker.services.configuration
before = user_service.get(user_id)
# Match `get_user`/`delete_user`, which 404 for an unknown id. Without this the request
# falls through to the service's `ValueError("User ... not found")` and the route's
# `except ValueError` reports it as a 400, contradicting this endpoint's own contract.
if before is None:
raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="User not found")
# The system user owns everything migrated from before multiuser support. Deactivating
# it would strand that content: its queue items stop at the dequeue gate, and reads and
# saves against system-owned media raise PermissionError. Promoting it or giving it a
# password is refused for a different reason — see `_assert_system_user_protected`,
# which is the backstop this friendly message fronts.
if user_id == SYSTEM_USER_ID and (
request.is_active is False or request.is_admin is True or request.password is not None
):
raise HTTPException(
status_code=status.HTTP_400_BAD_REQUEST,
detail=SYSTEM_USER_PROTECTED_DETAIL,
)
# Demoting or deactivating the last administrator is irreversible: authorization is
# derived from the database on every request, so the caller loses admin access
# immediately and no authenticated path back exists. It would also drop `has_admin()`
# to zero, which re-opens the unauthenticated `/auth/setup` endpoint to any caller.
# `delete_user` guards the same invariant.
if (
before.is_admin
and before.is_active
and (request.is_admin is False or request.is_active is False)
and user_service.count_admins() <= 1
):
raise HTTPException(
status_code=status.HTTP_400_BAD_REQUEST,
detail=LAST_ADMIN_DETAIL,View on GitHub (pinned to 0b6a024f2f)
Solutions
- Exclude the system user id from deactivation/promotion/password bulk operations.
- Leave the system user active and unprivileged — it is an internal ownership account, not a login.
- Create and manage real users via POST /users instead.
- Filter it client-side when enumerating users for edits.
Example fix
// before: blanket deactivate of every user
for (const u of users) await api.patch(`/users/${u.id}`, {is_active:false});
// after: skip the protected system user
for (const u of users) {
if (u.id === SYSTEM_USER_ID) continue;
await api.patch(`/users/${u.id}`, {is_active:false});
} Defensive patterns
Strategy: validation
Validate before calling
const SYSTEM_USER_ID = 'system'; // exported by the SDK
function canPatchUser(id, changes) {
if (id === SYSTEM_USER_ID &&
(changes.is_active === false || changes.is_admin === true || changes.password != null)) {
return ['system user cannot be deactivated, promoted, or given a password'];
}
return []; // [] => safe to PATCH
} Type guard
function isForbiddenSystemUserChange(changes) {
return changes.is_active === false ||
changes.is_admin === true ||
changes.password != null;
} Try / catch
try {
await api.patch(`/users/${id}`, changes);
} catch (e) {
if (e.status === 400 && e.detail.includes('system user')) {
console.warn('System user is protected; skipping');
} else throw e;
} Prevention
- Always skip SYSTEM_USER_ID in bulk deactivate/promote/password loops
- Treat the system user as an internal ownership account, never a login
- Create real users via POST /users rather than modifying the system row
- Filter the system user out of editable lists in admin UIs
When it happens
Trigger: PATCH /api/v1/users/{SYSTEM_USER_ID} with any of: body containing "is_active": false, "is_admin": true, or a non-null "password".
Common situations: Admin trying to 'clean up' the odd system row that has no password and cannot log in; scripts that deactivate all non-admin accounts and sweep the system user into the batch; attempts to assign the system user a password to log in as it.
Related errors
- Cannot remove the last administrator
- Administrator account already configured
- str(e)
- str(e) (ValueError from user service update, e.g. LastAdmini
- Current password is required to set a new password
AI-assisted analysis of invoke-ai/InvokeAI@0b6a024f2f (2026-08-29).
Data as JSON: /api/errors/b22560be9810cc60.
Report an issue: GitHub.