{"record":{"id":"2503456e7efe3119","repo":"Significant-Gravitas/AutoGPT","slug":"cannot-remove-the-last-workspace-admin-promote-an","errorCode":null,"errorMessage":"Cannot remove the last workspace admin. Promote another member to admin first.","messagePattern":"Cannot remove the last workspace admin\\. Promote another member to admin first\\.","errorType":"http","errorClass":"ValueError","httpStatus":400,"severity":"error","filePath":"autogpt_platform/backend/backend/api/features/orgs/team_db.py","lineNumber":223,"sourceCode":"    members = await list_team_members(ws_id)\n    return next(m for m in members if m.user_id == user_id)\n\n\nasync def remove_team_member(ws_id: str, user_id: str) -> None:\n    \"\"\"Remove a member from a workspace.\n\n    Guards against removing the last admin — workspace would become unmanageable.\n    \"\"\"\n    # Check if this would remove the last admin\n    member = await prisma.teammember.find_unique(\n        where={\"teamId_userId\": {\"teamId\": ws_id, \"userId\": user_id}}\n    )\n    if member and member.isAdmin:\n        admin_count = await prisma.teammember.count(\n            where={\"teamId\": ws_id, \"isAdmin\": True, \"status\": \"ACTIVE\"}\n        )\n        if admin_count <= 1:\n            raise ValueError(\n                \"Cannot remove the last workspace admin. \"\n                \"Promote another member to admin first.\"\n            )\n\n    await prisma.teammember.delete(\n        where={\"teamId_userId\": {\"teamId\": ws_id, \"userId\": user_id}}\n    )\n","sourceCodeStart":205,"sourceCodeEnd":231,"githubUrl":"https://github.com/Significant-Gravitas/AutoGPT/blob/9c8bb5550f446ba5d3046b78896578742495b3cf/autogpt_platform/backend/backend/api/features/orgs/team_db.py#L205-L231","documentation":"Raised by the remove-member flow in team_db when the member being removed is an ACTIVE admin and the workspace has admin_count <= 1. It prevents a workspace from becoming unmanageable with no one able to administer it. Plain ValueError from the DB layer.","triggerScenarios":"DELETE or remove call for a workspace member (team_db remove path around team_db.py:223) where that member has isAdmin=true and is the only ACTIVE admin in the workspace. Note the guard triggers on ANY removal path that hits it (delete member, and any flow reusing this check), including the member removing themselves.","commonSituations":"Sole admin tries to leave/remove themselves without promoting a successor; org downsizing removes the only admin; admin demotes then removes themselves in the wrong order; tests that never promote a second admin.","solutions":["Promote another ACTIVE member to admin first (update member with isAdmin=true), then retry the removal","If everyone else should not be admin, invite/add a new admin and then remove yourself","Transfer ownership: make sure the promote happens and is committed (ACTIVE status) before the remove call","In automated flows, sequence operations as promote -> verify admin_count >= 2 -> remove"],"exampleFix":"# before\nawait remove_team_member(ws_id, sole_admin_id)  # raises: last admin\n# after\nawait update_team_member(ws_id, other_member_id, data={\"isAdmin\": True})\nawait remove_team_member(ws_id, sole_admin_id)","handlingStrategy":"validation","validationCode":"const admins = (await listMembers(orgId, wsId)).filter(m => m.isAdmin && m.status === 'ACTIVE');\nif (admins.length <= 1 && admins[0]?.userId === targetUserId) {\n  throw new Error('Promote another admin before removing the last one');\n}","typeGuard":"function isLastActiveAdmin(m: TeamMemberResponse, activeAdmins: TeamMemberResponse[]): boolean {\n  return m.isAdmin && m.status === 'ACTIVE' && activeAdmins.length <= 1;\n}","tryCatchPattern":"try {\n  await removeTeamMember(orgId, wsId, userId);\n} catch (e) {\n  if (e.message.includes('last workspace admin')) {\n    await updateTeamMember(orgId, wsId, successorId, { isAdmin: true });\n    await removeTeamMember(orgId, wsId, userId);\n  } else throw e;\n}","preventionTips":["Always keep at least two ACTIVE admins per workspace","Sequence automated cleanup as promote -> verify -> remove"],"tags":["workspaces","orgs","members","admin","valueerror"],"backgroundTag":null,"analyzedSha":"9c8bb5550f446ba5d3046b78896578742495b3cf","analyzedAt":"2026-08-14T17:17:21.957Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}