invoke-ai/InvokeAI · error · HTTPException
str(e) (ValueError from user service delete, e.g. LastAdmini
Error message
str(e) (ValueError from user service delete, e.g. LastAdministratorError)
What it means
delete_user calls user_service.delete inside try/except ValueError; the service can raise ValueError (e.g. LastAdministratorError) if a race caused the pre-check to pass but the service still rejects the delete. The endpoint converts it to HTTP 400 with str(e) as the detail so the client gets a consistent 400 shape.
Source
Thrown at invokeai/app/api/routers/auth.py:692
if user_id == SYSTEM_USER_ID:
raise HTTPException(
status_code=status.HTTP_400_BAD_REQUEST,
detail=SYSTEM_USER_PROTECTED_DETAIL,
)
# Prevent deleting the last active admin. Same wording as the service backstop: this
# pre-check can lose a race and let the service reject the delete instead, and one
# endpoint should not report one condition two different ways.
if user.is_admin and user.is_active and user_service.count_admins() <= 1:
raise HTTPException(
status_code=status.HTTP_400_BAD_REQUEST,
detail=LAST_ADMIN_DETAIL,
)
try:
user_service.delete(user_id)
except ValueError as e:
raise HTTPException(status_code=status.HTTP_400_BAD_REQUEST, detail=str(e)) from e
# A deleted user must lose live access just like a deactivated one.
ApiDependencies.invoker.services.events.emit_user_access_changed(user_id=user_id, is_admin=False, is_active=False)
@auth_router.patch("/me", response_model=UserDTO)
def update_current_user(
request: Annotated[UserProfileUpdateRequest, Body(description="Profile fields to update")],
current_user: CurrentUser,
http_request: Request,
response: Response,
) -> UserDTO:
"""Update the current user's own profile.
To change the password, both ``current_password`` and ``new_password`` must
be provided. The current password is verified before the change is applied.
A password change signs out the account's *other* sessions: it bumps theView on GitHub (pinned to 0b6a024f2f)
Solutions
- Read the detail string to identify the specific ValueError (e.g. LastAdministratorError) and promote another active admin, then retry
- Refresh user/admin list before retrying the delete to re-run the pre-check with fresh data
- Avoid concurrent admin mutations on the same user set
Example fix
// before
try { await api.deleteUser(id) } catch (e) { /* unhandled 400 with service message */ }
// after
try {
await api.deleteUser(id);
} catch (e) {
if (e.detail?.includes('administrator')) { await api.updateUser(otherId, { is_admin: true }); await api.deleteUser(id); }
else throw e;
} Defensive patterns
Strategy: try-catch
Try / catch
try {
await api.deleteUser(userId);
} catch (e) {
if (e.response?.status === 400 && /administrator/i.test(e.response?.data?.detail ?? '')) {
await api.updateUser(otherAdminId, { is_admin: true });
await api.deleteUser(userId);
} else throw e;
} Prevention
- Serialize admin-mutation operations to avoid races on the last-admin check
- Re-fetch user/admin counts immediately before deletion
- Handle the 400 detail string generically since it carries the service message
When it happens
Trigger: DELETE /users/{id} where the last-admin pre-check passed but user_service.delete raises ValueError — typically a race where another admin was deactivated or the admin count changed between the check and the delete.
Common situations: Concurrent admin operations: one session deletes/deactivates the second admin while another session deletes what it believed was a non-last admin; stale UI state after another admin acted.
Related errors
- str(e) (ValueError from user service update, e.g. LastAdmini
- No external provider config fields provided
- Administrator account already configured
- str(e)
- The system user cannot be deleted, deactivated, promoted to
AI-assisted analysis of invoke-ai/InvokeAI@0b6a024f2f (2026-08-29).
Data as JSON: /api/errors/a967fe74b30f4bc8.
Report an issue: GitHub.