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
- 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.
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
- 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
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
- job belongs to a different user
- Invitation {invitation_id} not found
- This invitation was sent to a different email address
- ENTERPRISE subscription changes must be managed by an admini
- Failed to start OAuth flow
AI-assisted analysis of Significant-Gravitas/AutoGPT@9c8bb5550f (2026-08-14).
Data as JSON: /api/errors/06d013dc6c65587f.
Report an issue: GitHub.