{"record":{"id":"23e20599da2e164d","repo":"Significant-Gravitas/AutoGPT","slug":"cannot-self-join-a-private-workspace-request-an-i","errorCode":null,"errorMessage":"Cannot self-join a PRIVATE workspace. Request an invite.","messagePattern":"Cannot self-join a PRIVATE workspace\\. Request an invite\\.","errorType":"http","errorClass":"ValueError","httpStatus":400,"severity":"error","filePath":"autogpt_platform/backend/backend/api/features/orgs/team_db.py","lineNumber":105,"sourceCode":"    \"\"\"Delete a workspace. Cannot delete the default workspace.\"\"\"\n    ws = await prisma.team.find_unique(where={\"id\": ws_id})\n    if ws is None:\n        raise NotFoundError(f\"Workspace {ws_id} not found\")\n    if ws.isDefault:\n        raise ValueError(\"Cannot delete the default workspace\")\n\n    await prisma.team.delete(where={\"id\": ws_id})\n\n\nasync def join_team(ws_id: str, user_id: str, org_id: str) -> TeamResponse:\n    \"\"\"Self-join an OPEN workspace. User must be an org member.\"\"\"\n    ws = await prisma.team.find_unique(where={\"id\": ws_id})\n    if ws is None:\n        raise NotFoundError(f\"Workspace {ws_id} not found\")\n    if ws.orgId != org_id:\n        raise ValueError(\"Workspace does not belong to this organization\")\n    if ws.joinPolicy != \"OPEN\":\n        raise ValueError(\"Cannot self-join a PRIVATE workspace. Request an invite.\")\n\n    # Verify user is actually an org member\n    org_member = await prisma.orgmember.find_unique(\n        where={\"orgId_userId\": {\"orgId\": org_id, \"userId\": user_id}}\n    )\n    if org_member is None:\n        raise ValueError(f\"User {user_id} is not a member of the organization\")\n\n    # Check not already a member\n    existing = await prisma.teammember.find_unique(\n        where={\"teamId_userId\": {\"teamId\": ws_id, \"userId\": user_id}}\n    )\n    if existing:\n        return TeamResponse.from_db(ws)\n\n    await prisma.teammember.create(\n        data={\n            \"teamId\": ws_id,","sourceCodeStart":87,"sourceCodeEnd":123,"githubUrl":"https://github.com/Significant-Gravitas/AutoGPT/blob/9c8bb5550f446ba5d3046b78896578742495b3cf/autogpt_platform/backend/backend/api/features/orgs/team_db.py#L87-L123","documentation":"Raised by team_db.join_team when the workspace's joinPolicy is anything other than 'OPEN' (currently 'PRIVATE'). Self-join is only allowed on open workspaces; private ones require an explicit invitation via the invite/add-member flow. Plain ValueError from the DB layer.","triggerScenarios":"POST /api/orgs/{org_id}/workspaces/{ws_id}/join where the workspace was created (or updated) with join_policy='PRIVATE'. The check runs after the workspace exists and belongs to the org, so the caller is otherwise eligible.","commonSituations":"UI showing a 'Join' button on every workspace in the directory without filtering on joinPolicy; policy recently changed from OPEN to PRIVATE while users still have old links; users expecting org membership to imply workspace access.","solutions":["Check TeamResponse.joinPolicy === 'OPEN' before offering self-join; otherwise route the user to 'request invite'","An admin adds the user with POST .../workspaces/{ws_id}/members (add_team_member has no OPEN requirement)","An admin flips the workspace joinPolicy to 'OPEN' via PATCH if open enrollment is intended","Link the user to the invitation flow instead of the /join endpoint for PRIVATE workspaces"],"exampleFix":"// before\n{workspaces.map(ws => <JoinButton onClick={() => join(ws.id)} />)}\n// after\n{workspaces.map(ws =>\n  ws.joinPolicy === 'OPEN'\n    ? <JoinButton onClick={() => join(ws.id)} />\n    : <RequestInviteButton wsId={ws.id} />\n)}","handlingStrategy":"validation","validationCode":"const ws = await getWorkspace(orgId, wsId);\nif (ws.joinPolicy !== 'OPEN') {\n  redirectToAddMemberOrInviteFlow(wsId);\n}","typeGuard":"function isJoinableWorkspace(ws: TeamResponse): boolean {\n  return ws.joinPolicy === 'OPEN';\n}","tryCatchPattern":"try {\n  await joinTeam(orgId, wsId);\n} catch (e) {\n  if (e.message.includes('PRIVATE workspace')) {\n    showToast('This workspace is invite-only — request an invite.');\n  } else throw e;\n}","preventionTips":["Gate join buttons on joinPolicy === 'OPEN'","Keep an invite/request-access path for PRIVATE workspaces"],"tags":["workspaces","orgs","join","policy","valueerror"],"backgroundTag":null,"analyzedSha":"9c8bb5550f446ba5d3046b78896578742495b3cf","analyzedAt":"2026-08-14T17:17:21.957Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}