Significant-Gravitas/AutoGPT · error · HTTPException

Not a member of this organization

Error message

Not a member of this organization

What it means

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.

Source

Thrown at autogpt_platform/backend/backend/api/features/orgs/routes.py:39

    OrgMemberResponse,
    OrgResponse,
    TransferOwnershipRequest,
    UpdateMemberRequest,
    UpdateOrgData,
    UpdateOrgRequest,
)

router = APIRouter()


def _verify_org_path(ctx: RequestContext, org_id: str) -> None:
    """Ensure the authenticated user's active org matches the path parameter.

    Prevents authorization bypass where a user sends X-Org-Id for org A
    but targets org B in the URL path.
    """
    if ctx.org_id != org_id:
        raise HTTPException(403, detail="Not a member of this organization")


@router.post(
    "",
    summary="Create organization",
    tags=["orgs"],
    dependencies=[Security(requires_user)],
)
async def create_org(
    request: CreateOrgRequest,
    user_id: Annotated[str, Security(get_user_id)],
) -> OrgResponse:
    return await org_db.create_org(
        name=request.name,
        slug=request.slug,
        user_id=user_id,
        description=request.description,
    )

View on GitHub (pinned to 9c8bb5550f)

Solutions

  1. Ensure the X-Org-Id header (or active-org context) matches the org_id used in the URL path for every request.
  2. After an org switch, re-render routes so path parameters are regenerated from the active org.
  3. Centralize org context in one API client that derives both header and path from the same value.
  4. If hitting the API manually, copy the org id from the same source for both header and URL.

Example fix

// before
api.defaults.headers['X-Org-Id'] = activeOrgId; // set once, never updated
await api.get(`/api/orgs/${routeOrgId}/members`);
// after — derive header and path from the same value
await api.get(`/api/orgs/${activeOrgId}/members`, {
  headers: { 'X-Org-Id': activeOrgId },
});
Defensive patterns

Strategy: validation

Validate before calling

function assertOrgMatch(headerOrgId: string, pathOrgId: string) {
  if (headerOrgId !== pathOrgId) {
    throw new Error(`X-Org-Id ${headerOrgId} != path org ${pathOrgId}`);
  }
}

Try / catch

try {
  await api.get(`/api/orgs/${orgId}/members`, { headers: { 'X-Org-Id': orgId } });
} catch (e) {
  if (e.status === 403 && e.detail === 'Not a member of this organization') {
    await refreshActiveOrg(); return;
  }
  throw e;
}

Prevention

When it happens

Trigger: 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.

Common situations: 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.

Related errors


AI-assisted analysis of Significant-Gravitas/AutoGPT@9c8bb5550f (2026-08-14). Data as JSON: /api/errors/06d013dc6c65587f. Report an issue: GitHub.