{"record":{"id":"06d013dc6c65587f","repo":"Significant-Gravitas/AutoGPT","slug":"not-a-member-of-this-organization-06d013","errorCode":null,"errorMessage":"Not a member of this organization","messagePattern":"Not a member of this organization","errorType":"http","errorClass":"HTTPException","httpStatus":403,"severity":"error","filePath":"autogpt_platform/backend/backend/api/features/orgs/routes.py","lineNumber":39,"sourceCode":"    OrgMemberResponse,\n    OrgResponse,\n    TransferOwnershipRequest,\n    UpdateMemberRequest,\n    UpdateOrgData,\n    UpdateOrgRequest,\n)\n\nrouter = APIRouter()\n\n\ndef _verify_org_path(ctx: RequestContext, org_id: str) -> None:\n    \"\"\"Ensure the authenticated user's active org matches the path parameter.\n\n    Prevents authorization bypass where a user sends X-Org-Id for org A\n    but targets org B in the URL path.\n    \"\"\"\n    if ctx.org_id != org_id:\n        raise HTTPException(403, detail=\"Not a member of this organization\")\n\n\n@router.post(\n    \"\",\n    summary=\"Create organization\",\n    tags=[\"orgs\"],\n    dependencies=[Security(requires_user)],\n)\nasync def create_org(\n    request: CreateOrgRequest,\n    user_id: Annotated[str, Security(get_user_id)],\n) -> OrgResponse:\n    return await org_db.create_org(\n        name=request.name,\n        slug=request.slug,\n        user_id=user_id,\n        description=request.description,\n    )","sourceCodeStart":21,"sourceCodeEnd":57,"githubUrl":"https://github.com/Significant-Gravitas/AutoGPT/blob/9c8bb5550f446ba5d3046b78896578742495b3cf/autogpt_platform/backend/backend/api/features/orgs/routes.py#L21-L57","documentation":"Raised by the _verify_org_path helper in the orgs routes when the authenticated user's active org (ctx.org_id, derived from the X-Org-Id header) does not equal the org_id in the URL path. It blocks authorization bypass where a user sends X-Org-Id for org A while targeting org B in the path. HTTP 403.","triggerScenarios":"Calling any /api/orgs/{org_id}/... endpoint where the path org differs from the X-Org-Id header (or whatever sets the RequestContext org). Common after switching orgs in the UI while deep links still carry the old org id.","commonSituations":"Frontend forgets to update X-Org-Id after org switch; manually crafted requests or Postman collections with mismatched header/path; stale browser tab from before an org change.","solutions":["Ensure the X-Org-Id header (or active-org context) matches the org_id used in the URL path for every request.","After an org switch, re-render routes so path parameters are regenerated from the active org.","Centralize org context in one API client that derives both header and path from the same value.","If hitting the API manually, copy the org id from the same source for both header and URL."],"exampleFix":"// before\napi.defaults.headers['X-Org-Id'] = activeOrgId; // set once, never updated\nawait api.get(`/api/orgs/${routeOrgId}/members`);\n// after — derive header and path from the same value\nawait api.get(`/api/orgs/${activeOrgId}/members`, {\n  headers: { 'X-Org-Id': activeOrgId },\n});","handlingStrategy":"validation","validationCode":"function assertOrgMatch(headerOrgId: string, pathOrgId: string) {\n  if (headerOrgId !== pathOrgId) {\n    throw new Error(`X-Org-Id ${headerOrgId} != path org ${pathOrgId}`);\n  }\n}","typeGuard":null,"tryCatchPattern":"try {\n  await api.get(`/api/orgs/${orgId}/members`, { headers: { 'X-Org-Id': orgId } });\n} catch (e) {\n  if (e.status === 403 && e.detail === 'Not a member of this organization') {\n    await refreshActiveOrg(); return;\n  }\n  throw e;\n}","preventionTips":["Derive X-Org-Id and URL path from the same org variable in one client wrapper","Update all in-flight requests after an org switch","Never hardcode org ids in Postman collections"],"tags":["orgs","authorization","http-403","headers"],"backgroundTag":null,"analyzedSha":"9c8bb5550f446ba5d3046b78896578742495b3cf","analyzedAt":"2026-08-14T17:17:21.957Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}