Significant-Gravitas/AutoGPT · error · HTTPException

Teams not found in this organization: {invalid}

Error message

Teams not found in this organization: {invalid}

What it means

Raised by POST /api/orgs/{org_id}/invitations when one or more team_ids in InvitationCreateRequest do not reference teams that exist in the database and belong to the org in the URL path. The check exists because the accept path's add_team_member re-validates and silently skips failures, so a poisoned invitation would only fail quietly at accept time; the create endpoint fails loudly instead. It is an HTTP 400 HTTPException.

Source

Thrown at autogpt_platform/backend/backend/api/features/orgs/invitation_routes.py:61

    org_id: str,
    request: CreateInvitationRequest,
    ctx: Annotated[
        RequestContext,
        Security(requires_org_permission(OrgAction.MANAGE_MEMBERS)),
    ],
) -> InvitationCreateResponse:
    _verify_org_path(ctx, org_id)

    # Reject team IDs outside this org at create time. The accept path's
    # add_team_member re-validates (and silently skips failures), so
    # without this check a poisoned invitation would fail silently at
    # accept instead of loudly at create.
    if request.team_ids:
        teams = await prisma.team.find_many(where={"id": {"in": request.team_ids}})
        valid_ids = {t.id for t in teams if t.orgId == org_id}
        invalid = [t for t in request.team_ids if t not in valid_ids]
        if invalid:
            raise HTTPException(
                400,
                detail=f"Teams not found in this organization: {invalid}",
            )

    expires_at = datetime.now(timezone.utc) + timedelta(days=INVITATION_TTL_DAYS)

    invitation = await prisma.orginvitation.create(
        data={
            "orgId": org_id,
            "email": request.email,
            "isAdmin": request.is_admin,
            "isBillingManager": request.is_billing_manager,
            "expiresAt": expires_at,
            "invitedByUserId": ctx.user_id,
            "teamIds": request.team_ids,
        }
    )

View on GitHub (pinned to 9c8bb5550f)

Solutions

  1. Re-fetch the team list for the current org (GET /api/orgs/{org_id}/teams) immediately before submitting and rebuild team_ids from it.
  2. Verify every team_id in the request payload matches an id from that org's team list; drop or fix any that do not.
  3. If the team should exist, check the Team table (prisma.team) for the id and confirm its orgId equals the org_id in the URL path.
  4. Handle the 400 by parsing the detail list of invalid IDs and refreshing the user's team selection UI.

Example fix

// before
const res = await api.post(`/api/orgs/${orgId}/invitations`, {
  email, team_ids: selectedTeamIds, // may contain stale ids
});
// after
const teams = await api.get(`/api/orgs/${orgId}/teams`).then(r => r.data);
const validIds = new Set(teams.map(t => t.id));
const team_ids = selectedTeamIds.filter(id => validIds.has(id));
if (selectedTeamIds.length !== team_ids.length) {
  throw new Error('Some selected teams no longer exist in this organization');
}
const res = await api.post(`/api/orgs/${orgId}/invitations`, { email, team_ids });
Defensive patterns

Strategy: validation

Validate before calling

const teams = await api.get(`/api/orgs/${orgId}/teams`).then(r => r.data);
const validIds = new Set(teams.map(t => t.id));
const ok = selectedTeamIds.every(id => validIds.has(id));
if (!ok) throw new Error('Invalid team ids for this org');

Try / catch

try {
  await api.post(`/api/orgs/${orgId}/invitations`, payload);
} catch (e) {
  if (e.status === 400 && /Teams not found/.test(e.detail)) {
    const invalid = JSON.parse(e.detail.split(': ')[1]); // ids to drop
    await refreshTeams();
  } else throw e;
}

Prevention

When it happens

Trigger: Calling create invitation with team_ids that are deleted, typo'd, belong to a different organization, or were created in another org (valid_ids filters on t.orgId == org_id). Also triggered when the caller copies team IDs from a different environment (staging IDs used against production).

Common situations: Frontend sends stale team IDs cached from a previous org switch; team was deleted between the picker load and form submit; test fixtures use hardcoded team IDs that drift after migrations; multi-tenant confusion where X-Org-Id header org differs from the team's org.

Related errors


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