{"record":{"id":"8d2222dfea5521d8","repo":"Significant-Gravitas/AutoGPT","slug":"teams-not-found-in-this-organization-invalid","errorCode":null,"errorMessage":"Teams not found in this organization: {invalid}","messagePattern":"Teams not found in this organization: (.+?)","errorType":"http","errorClass":"HTTPException","httpStatus":400,"severity":"error","filePath":"autogpt_platform/backend/backend/api/features/orgs/invitation_routes.py","lineNumber":61,"sourceCode":"    org_id: str,\n    request: CreateInvitationRequest,\n    ctx: Annotated[\n        RequestContext,\n        Security(requires_org_permission(OrgAction.MANAGE_MEMBERS)),\n    ],\n) -> InvitationCreateResponse:\n    _verify_org_path(ctx, org_id)\n\n    # Reject team IDs outside this org at create time. The accept path's\n    # add_team_member re-validates (and silently skips failures), so\n    # without this check a poisoned invitation would fail silently at\n    # accept instead of loudly at create.\n    if request.team_ids:\n        teams = await prisma.team.find_many(where={\"id\": {\"in\": request.team_ids}})\n        valid_ids = {t.id for t in teams if t.orgId == org_id}\n        invalid = [t for t in request.team_ids if t not in valid_ids]\n        if invalid:\n            raise HTTPException(\n                400,\n                detail=f\"Teams not found in this organization: {invalid}\",\n            )\n\n    expires_at = datetime.now(timezone.utc) + timedelta(days=INVITATION_TTL_DAYS)\n\n    invitation = await prisma.orginvitation.create(\n        data={\n            \"orgId\": org_id,\n            \"email\": request.email,\n            \"isAdmin\": request.is_admin,\n            \"isBillingManager\": request.is_billing_manager,\n            \"expiresAt\": expires_at,\n            \"invitedByUserId\": ctx.user_id,\n            \"teamIds\": request.team_ids,\n        }\n    )\n","sourceCodeStart":43,"sourceCodeEnd":79,"githubUrl":"https://github.com/Significant-Gravitas/AutoGPT/blob/9c8bb5550f446ba5d3046b78896578742495b3cf/autogpt_platform/backend/backend/api/features/orgs/invitation_routes.py#L43-L79","documentation":"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.","triggerScenarios":"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).","commonSituations":"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.","solutions":["Re-fetch the team list for the current org (GET /api/orgs/{org_id}/teams) immediately before submitting and rebuild team_ids from it.","Verify every team_id in the request payload matches an id from that org's team list; drop or fix any that do not.","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.","Handle the 400 by parsing the detail list of invalid IDs and refreshing the user's team selection UI."],"exampleFix":"// before\nconst res = await api.post(`/api/orgs/${orgId}/invitations`, {\n  email, team_ids: selectedTeamIds, // may contain stale ids\n});\n// after\nconst teams = await api.get(`/api/orgs/${orgId}/teams`).then(r => r.data);\nconst validIds = new Set(teams.map(t => t.id));\nconst team_ids = selectedTeamIds.filter(id => validIds.has(id));\nif (selectedTeamIds.length !== team_ids.length) {\n  throw new Error('Some selected teams no longer exist in this organization');\n}\nconst res = await api.post(`/api/orgs/${orgId}/invitations`, { email, team_ids });","handlingStrategy":"validation","validationCode":"const teams = await api.get(`/api/orgs/${orgId}/teams`).then(r => r.data);\nconst validIds = new Set(teams.map(t => t.id));\nconst ok = selectedTeamIds.every(id => validIds.has(id));\nif (!ok) throw new Error('Invalid team ids for this org');","typeGuard":null,"tryCatchPattern":"try {\n  await api.post(`/api/orgs/${orgId}/invitations`, payload);\n} catch (e) {\n  if (e.status === 400 && /Teams not found/.test(e.detail)) {\n    const invalid = JSON.parse(e.detail.split(': ')[1]); // ids to drop\n    await refreshTeams();\n  } else throw e;\n}","preventionTips":["Always build team_ids from a fresh org-scoped team list at submit time","Drop cached team ids when the active org changes","Parse the 400 detail list to auto-heal the picker"],"tags":["invitations","orgs","teams","validation","http-400"],"backgroundTag":null,"analyzedSha":"9c8bb5550f446ba5d3046b78896578742495b3cf","analyzedAt":"2026-08-14T17:17:21.957Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}