calcom/cal.diy · error · ForbiddenException
RolesGuard - User is not part of the team with id=${teamId}
Error message
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}. What it means
ForbiddenException from RolesGuard in the combined org+team branch when: (a) the allowedRole is a TEAM role, (b) the user IS a member of the org but NOT as ORG_ADMIN/ORG_OWNER (so org-over-team escalation does not apply), and (c) the user has no teamMembership row. Because org admins/owners are auto-allowed for any team role, this only fires for non-admin org members who are also absent from the specific team.
Source
Thrown at apps/api/v2/src/modules/auth/guards/roles/roles.guard.ts:143
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 role
canAccess = hasMinimumRole({
checkRole: `TEAM_${teamMembership.role}`,
minimumRole: allowedRole,
roles: TEAM_ROLES,
});
}
}
// if allowed role is a ORG ROLE, check org membersip role
else if (ORG_ROLES.includes(allowedRole as unknown as (typeof ORG_ROLES)[number])) {
canAccess = hasMinimumRole({
checkRole: `ORG_${orgMembership.role}`,
minimumRole: allowedRole,View on GitHub (pinned to 176037d0af)
Solutions
- Have a team admin/owner add the user to the team, OR have an org owner promote the user to ORG_ADMIN/ORG_OWNER (which grants cross-team access).
- Confirm the teamId matches a team inside the org the user belongs to.
- Clear the RolesGuard Redis cache if a membership/role was just updated.
- For tests, seed a team Membership row (or promote to ORG_ADMIN in the org Membership).
Defensive patterns
Strategy: validation
Validate before calling
const orgMembership = await membershipRepository.findMembershipByOrgId(Number(orgId), user.id);
const teamMembership = await membershipRepository.findMembershipByTeamId(Number(teamId), user.id);
const isOrgPrivileged = orgMembership && ['ADMIN','OWNER'].includes(orgMembership.role);
if (!isOrgPrivileged && !teamMembership) {
// user must either be added to the team OR promoted to ORG_ADMIN/ORG_OWNER
} Try / catch
try {
await client.get(`/v2/orgs/${orgId}/teams/${teamId}/members`);
} catch (e) {
if (e.status === 403 && /not part of the team.*not an admin nor an owner/.test(e.message)) {
// request team membership OR org owner promotion
}
throw e;
} Prevention
- Non-admin org members must also be team members to access team-scoped routes.
- Promote to ORG_ADMIN/ORG_OWNER to grant cross-team access.
- Clear the RolesGuard cache after role/membership changes.
When it happens
Trigger: Calling an org+team route requiring a TEAM_* role, where the user is e.g. an ORG_MEMBER of the org and has no Membership in the target team. The guard logs both the team-absence and the not-admin/owner context.
Common situations: Org member tries to manage a team they weren't added to; user was removed from the team but retained org membership; recent role change not yet reflected (cache); test seed has org Membership but not team Membership.
Related errors
- RolesGuard - User is not part of the organization with id=${
- 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/ed37ffac9556c095.
Report an issue: GitHub.