calcom/cal.diy · error · ForbiddenException

RolesGuard - User is not a member of the team with id=${team

Error message

RolesGuard - User is not a member of the team with id=${teamId}.

What it means

ForbiddenException from RolesGuard when checking role access for a team-scoped (teamId present, orgId absent) request and membershipRepository.findMembershipByTeamId(teamId, user.id) returns null — the user has no Membership in that team, so the role check is skipped and a 403 is thrown.

Source

Thrown at apps/api/v2/src/modules/auth/guards/roles/roles.guard.ts:112

          `RolesGuard - User is not a member of the organization with id=${orgId}.`
        );
      }

      if (ORG_ROLES.includes(allowedRole as unknown as (typeof ORG_ROLES)[number])) {
        canAccess = hasMinimumRole({
          checkRole: `ORG_${membership.role}`,
          minimumRole: allowedRole,
          roles: ORG_ROLES,
        });
      }
    }

    // Checking the role of the user within the team
    else if (Boolean(teamId) && !Boolean(orgId)) {
      const membership = await this.membershipRepository.findMembershipByTeamId(Number(teamId), user.id);
      if (!membership) {
        this.logger.log(`User (${user.id}) is not a member of the team (${teamId}), denying access.`);
        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}.`);

View on GitHub (pinned to 176037d0af)

Solutions

  1. Have a team admin/owner add the user to the team and have the user accept.
  2. Confirm the teamId in the request path matches a team the user belongs to.
  3. If access was just granted, clear the RolesGuard Redis cache to drop the stale 'false'.
  4. For tests, seed a team Membership for the user.
Defensive patterns

Strategy: validation

Validate before calling

const membership = await membershipRepository.findMembershipByTeamId(Number(teamId), user.id);
if (!membership) {
  // prompt user to be added to the team before calling
}

Try / catch

try {
  await client.get(`/v2/teams/${teamId}/members`);
} catch (e) {
  if (e.status === 403 && /not a member of the team/.test(e.message)) {
    // ask user to join the team
  }
  throw e;
}

Prevention

When it happens

Trigger: Calling a team-scoped route (teamId set, no orgId) where the authenticated user has no Membership row in that team. The guard logs 'User (id) is not a member of the team (teamId), denying access.'

Common situations: User was removed from the team; team invite pending; teamId typo; user is in the parent org but never added to the specific team; test user not seeded with a team Membership.

Related errors


AI-assisted analysis of calcom/cal.diy@176037d0af (2026-08-12). Data as JSON: /api/errors/d7fff4c47bfd996b. Report an issue: GitHub.