{"record":{"id":"b22560be9810cc60","repo":"invoke-ai/InvokeAI","slug":"the-system-user-cannot-be-deleted-deactivated-pr","errorCode":null,"errorMessage":"The system user cannot be deleted, deactivated, promoted to administrator, or given a password","messagePattern":"The system user cannot be deleted, deactivated, promoted to administrator, or given a password","errorType":"http","errorClass":"HTTPException","httpStatus":400,"severity":"error","filePath":"invokeai/app/api/routers/auth.py","lineNumber":587,"sourceCode":"    \"\"\"\n    user_service = ApiDependencies.invoker.services.users\n    config = ApiDependencies.invoker.services.configuration\n    before = user_service.get(user_id)\n    # Match `get_user`/`delete_user`, which 404 for an unknown id. Without this the request\n    # falls through to the service's `ValueError(\"User ... not found\")` and the route's\n    # `except ValueError` reports it as a 400, contradicting this endpoint's own contract.\n    if before is None:\n        raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail=\"User not found\")\n\n    # The system user owns everything migrated from before multiuser support. Deactivating\n    # it would strand that content: its queue items stop at the dequeue gate, and reads and\n    # saves against system-owned media raise PermissionError. Promoting it or giving it a\n    # password is refused for a different reason — see `_assert_system_user_protected`,\n    # which is the backstop this friendly message fronts.\n    if user_id == SYSTEM_USER_ID and (\n        request.is_active is False or request.is_admin is True or request.password is not None\n    ):\n        raise HTTPException(\n            status_code=status.HTTP_400_BAD_REQUEST,\n            detail=SYSTEM_USER_PROTECTED_DETAIL,\n        )\n\n    # Demoting or deactivating the last administrator is irreversible: authorization is\n    # derived from the database on every request, so the caller loses admin access\n    # immediately and no authenticated path back exists. It would also drop `has_admin()`\n    # to zero, which re-opens the unauthenticated `/auth/setup` endpoint to any caller.\n    # `delete_user` guards the same invariant.\n    if (\n        before.is_admin\n        and before.is_active\n        and (request.is_admin is False or request.is_active is False)\n        and user_service.count_admins() <= 1\n    ):\n        raise HTTPException(\n            status_code=status.HTTP_400_BAD_REQUEST,\n            detail=LAST_ADMIN_DETAIL,","sourceCodeStart":569,"sourceCodeEnd":605,"githubUrl":"https://github.com/invoke-ai/InvokeAI/blob/0b6a024f2ff6a86bfb953dcdb9cc504ef7397a06/invokeai/app/api/routers/auth.py#L569-L605","documentation":"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.","triggerScenarios":"PATCH /api/v1/users/{SYSTEM_USER_ID} with any of: body containing \"is_active\": false, \"is_admin\": true, or a non-null \"password\".","commonSituations":"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.","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."],"exampleFix":"// before: blanket deactivate of every user\nfor (const u of users) await api.patch(`/users/${u.id}`, {is_active:false});\n// after: skip the protected system user\nfor (const u of users) {\n  if (u.id === SYSTEM_USER_ID) continue;\n  await api.patch(`/users/${u.id}`, {is_active:false});\n}","handlingStrategy":"validation","validationCode":"const SYSTEM_USER_ID = 'system'; // exported by the SDK\nfunction canPatchUser(id, changes) {\n  if (id === SYSTEM_USER_ID &&\n      (changes.is_active === false || changes.is_admin === true || changes.password != null)) {\n    return ['system user cannot be deactivated, promoted, or given a password'];\n  }\n  return []; // [] => safe to PATCH\n}","typeGuard":"function isForbiddenSystemUserChange(changes) {\n  return changes.is_active === false ||\n         changes.is_admin === true ||\n         changes.password != null;\n}","tryCatchPattern":"try {\n  await api.patch(`/users/${id}`, changes);\n} catch (e) {\n  if (e.status === 400 && e.detail.includes('system user')) {\n    console.warn('System user is protected; skipping');\n  } else throw e;\n}","preventionTips":["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"],"tags":["http-400","users","protected-resource","auth"],"backgroundTag":"protected-resource-modification","analyzedSha":"0b6a024f2ff6a86bfb953dcdb9cc504ef7397a06","analyzedAt":"2026-08-29T04:46:49.967Z","schemaVersion":2},"datasetVersion":"2026-08-29T07:17:48.351Z"}