calcom/cal.diy · error · ForbiddenException
RolesGuard - User is not part of the organization with id=${
Error message
RolesGuard - User is not part of the organization with id=${orgId}. What it means
ForbiddenException from RolesGuard when BOTH orgId and teamId are present, the request reaches the combined org+team branch, and membershipRepository.findMembershipByOrgId(orgId, user.id) returns null — the user is not part of the organization that owns the team. This throws BEFORE the team membership check, because org-level absence means no inherited team access either.
Source
Thrown at apps/api/v2/src/modules/auth/guards/roles/roles.guard.ts:130
throw new ForbiddenException(`RolesGuard - User is not a member of the team with id=${teamId}.`);
}
if (TEAM_ROLES.includes(allowedRole as unknown as (typeof TEAM_ROLES)[number])) {
canAccess = hasMinimumRole({
checkRole: `TEAM_${membership.role}`,
minimumRole: allowedRole,
roles: TEAM_ROLES,
});
}
}
// Checking the role for team and org, org is above team in term of permissions
else if (Boolean(teamId) && Boolean(orgId)) {
const teamMembership = await this.membershipRepository.findMembershipByTeamId(Number(teamId), user.id);
const orgMembership = await this.membershipRepository.findMembershipByOrgId(Number(orgId), user.id);
if (!orgMembership) {
this.logger.log(`User (${user.id}) is not part of the organization (${orgId}), denying access.`);
throw new ForbiddenException(`RolesGuard - User is not part of the organization with id=${orgId}.`);
}
// if the role checked is a TEAM role
if (TEAM_ROLES.includes(allowedRole as unknown as (typeof TEAM_ROLES)[number])) {
// if the user is admin or owner of org, allow request because org > team
if (`ORG_${orgMembership.role}` === "ORG_ADMIN" || `ORG_${orgMembership.role}` === "ORG_OWNER") {
canAccess = true;
} else {
if (!teamMembership) {
this.logger.log(
`User (${user.id}) is not part of the team (${teamId}) and/or, is not an admin nor an owner of the organization (${orgId}).`
);
throw new ForbiddenException(
`RolesGuard - User is not part of the team with id=${teamId} and/or, is not an admin nor an owner of the organization with id=${orgId}.`
);
}
// if user is not admin nor an owner of org, and is part of the team, then check user team membership roleView on GitHub (pinned to 176037d0af)
Solutions
- Have an org admin add the user to the organization (not just the team).
- Verify the orgId and teamId belong together (the team's parent org must equal the orgId).
- If the user was just added to the org, clear the RolesGuard Redis cache.
- For tests, seed both the org Membership (the combined branch checks org first).
Defensive patterns
Strategy: validation
Validate before calling
const orgMembership = await membershipRepository.findMembershipByOrgId(Number(orgId), user.id);
if (!orgMembership) {
// user must join the org first; team access alone won't satisfy the combined check
} Try / catch
try {
await client.get(`/v2/orgs/${orgId}/teams/${teamId}`);
} catch (e) {
if (e.status === 403 && /not part of the organization/.test(e.message)) {
// user needs org membership, not just team
}
throw e;
} Prevention
- Add the user to the organization, not just the team, when both scopes are required.
- Verify the teamId is actually a child of the orgId you supplied.
- Seed both Memberships in tests.
When it happens
Trigger: Calling a route that passes both orgId and teamId where the user has no Membership in the organization. Even if the user is a member of the team in isolation, the org-membership gate fails first.
Common situations: User belongs to the team but the team was moved/reparented to a different org; org membership revoked; orgId/teamId pair is inconsistent (teamId belongs to a different org than the orgId supplied); cross-tenant access.
Related errors
- RolesGuard - User is not part of the team with id=${teamId}
- RolesGuard - user with id=${user.id} does not have the minim
- RolesGuard - User is not a member of the organization with i
- RolesGuard - User is not a member of the team with id=${team
- GetOrgId decorator: Organization ID not found
AI-assisted analysis of calcom/cal.diy@176037d0af (2026-08-12).
Data as JSON: /api/errors/fcd8e36552556b08.
Report an issue: GitHub.