calcom/cal.diy · error · BadRequestException
Cannot redirect to this user.
Error message
Cannot redirect to this user.
What it means
Thrown by checkUserEligibleForRedirect() when a toUserId is provided but usersRepository.findUserOOORedirectEligible() returns null. The repository query requires the target user to exist AND to be a member of a team in which the source user (userId) is also an accepted member. So the redirect target must be a current teammate of the redirector.
Source
Thrown at apps/api/v2/src/modules/ooo/services/ooo.service.ts:61
isStartBeforeEnd(start?: Date, end?: Date) {
if ((end && !start) || (start && !end)) {
throw new BadRequestException("Please specify both ooo start and end time.");
}
if (start && end) {
if (start.getTime() > end.getTime()) {
throw new BadRequestException("Start date must be before end date.");
}
}
return true;
}
async checkUserEligibleForRedirect(userId: number, toUserId?: number) {
if (toUserId) {
const user = await this.usersRepository.findUserOOORedirectEligible(userId, toUserId);
if (!user) {
throw new BadRequestException("Cannot redirect to this user.");
}
}
}
async checkExistingOooRedirect(userId: number, start?: Date, end?: Date, toUserId?: number) {
if (start && end) {
const existingOooRedirect = await this.oooRepository.findExistingOooRedirect(
userId,
start,
end,
toUserId
);
if (existingOooRedirect) {
throw new BadRequestException("Booking redirect infinite not allowed.");
}
}
}View on GitHub (pinned to 176037d0af)
Solutions
- Restrict the redirect-target picker to users returned by the teams/membership endpoint for the current user's teams.
- Re-fetch team membership when the picker opens rather than caching, so removed members are excluded.
- If the 400 occurs, prompt the user to pick a current teammate and resubmit.
Example fix
// before
await api.post('/ooo', { start, end, toUserId: arbitraryUserId });
// after — only offer eligible teammates
const teammates = await api.get('/teams/members', { accepted: true });
await api.post('/ooo', { start, end, toUserId: teammates[0].userId }); Defensive patterns
Strategy: validation
Validate before calling
async function pickEligibleRedirectTarget(currentUserId: number): Promise<number> {
const members = await api.get('/teams/members', { params: { accepted: true } });
const eligible = members.filter((m: { userId: number }) => m.userId !== currentUserId);
if (!eligible.length) throw new Error('No eligible teammate to redirect to');
return eligible[0].userId;
} Type guard
const isTeammateOf = async (userId: number, candidateId: number): Promise<boolean> => {
const teams = await api.get('/teams', { params: { userId } });
return teams.some((t: { members: { userId: number }[] }) =>
t.members.some((m: { userId: number }) => m.userId === candidateId));
}; Prevention
- Only populate the redirect picker from the current user's accepted team memberships.
- Re-fetch membership when the picker opens.
- Omit toUserId entirely if no eligible teammate exists.
When it happens
Trigger: POST/PATCH /v2/ooo with toUserId pointing to a user who is not on any shared team with the authenticated user, a user who left the team, a user who was never invited/accepted, or a non-existent user id.
Common situations: Frontend offering redirect-to any org member instead of only teammates; stale team membership after a member was removed; cross-organization redirect attempts; passing a userId from a different tenant.
Related errors
- Please specify both ooo start and end time.
- Start date must be before end date.
- Booking redirect infinite not allowed.
- Cannot redirect to self.
- ApiKeysService - This endpoint can only be accessed using an
AI-assisted analysis of calcom/cal.diy@176037d0af (2026-08-12).
Data as JSON: /api/errors/a2df6a1ce757804a.
Report an issue: GitHub.