calcom/cal.diy · error · BadRequestException
Cannot redirect to self.
Error message
Cannot redirect to self.
What it means
BadRequestException thrown by checkRedirectToSelf() when toUserId is provided and equals userId. An OOO entry cannot redirect bookings back to the same user it is created for — that would be a self-loop.
Source
Thrown at apps/api/v2/src/modules/ooo/services/ooo.service.ts:93
if (existingOooRedirect) {
throw new BadRequestException("Booking redirect infinite not allowed.");
}
}
}
async checkDuplicateOOOEntry(userId: number, start?: Date, end?: Date) {
if (start && end) {
const duplicateEntry = await this.oooRepository.getOooByUserIdAndTime(userId, start, end);
if (duplicateEntry) {
throw new ConflictException("Ooo entry already exists.");
}
}
}
checkRedirectToSelf(userId: number, toUserId?: number) {
if (toUserId && toUserId === userId) {
throw new BadRequestException("Cannot redirect to self.");
}
}
async checkIsValidOOO(userId: number, ooo: CreateOutOfOfficeEntryDto | UpdateOutOfOfficeEntryDto) {
this.isStartBeforeEnd(ooo.start, ooo.end);
await this.checkExistingOooRedirect(userId, ooo.start, ooo.end, ooo.toUserId);
await this.checkDuplicateOOOEntry(userId, ooo.start, ooo.end);
await this.checkRedirectToSelf(userId, ooo.toUserId);
await this.checkUserEligibleForRedirect(userId, ooo.toUserId);
}
async createUserOOO(userId: number, body: CreateOutOfOfficeEntryDto) {
await this.checkIsValidOOO(userId, body);
const { reason, ...rest } = body;
const ooo = await this.oooRepository.createUserOOO({
...rest,
userId,
reasonId: OOO_REASON_TO_REASON_ID[reason ?? OutOfOfficeReason["UNSPECIFIED"]],View on GitHub (pinned to 176037d0af)
Solutions
- Exclude the current user from the redirect-target picker list.
- Client-side, clear or block submission when toUserId === currentUserId.
- If the user genuinely wants no redirect, omit toUserId entirely rather than setting it to self.
Example fix
// before toUserId = currentUser.id; // self // after toUserId = teammates.find(t => t.userId !== currentUser.id)?.userId; // and omit the field entirely if no other teammate is available
Defensive patterns
Strategy: validation
Validate before calling
function sanitizeRedirectTarget(currentUserId: number, toUserId?: number): number | undefined {
if (toUserId === undefined) return undefined;
if (toUserId === currentUserId) throw new Error('Cannot redirect to self');
return toUserId;
} Type guard
const isOtherUser = (currentUserId: number, toUserId?: number): boolean => toUserId !== undefined && toUserId !== currentUserId;
Prevention
- Exclude the current user from the redirect picker options.
- Clear toUserId if no teammate is selected instead of defaulting to self.
- Block submission client-side when toUserId === currentUserId.
When it happens
Trigger: POST/PATCH /v2/ooo where the authenticated user sets toUserId to their own user id; a picker whose default option is the current user; copying a userId from the session into the redirect field.
Common situations: UI defaulting the redirect target to 'me'; account-switching where the current user id changes but the form keeps the old toUserId; passing the whole user object's id without filtering self.
Related errors
- Please specify both ooo start and end time.
- Start date must be before end date.
- Cannot redirect to this user.
- Booking redirect infinite not allowed.
- Cannot add ${newGuestCount} guests. This booking already has
AI-assisted analysis of calcom/cal.diy@176037d0af (2026-08-12).
Data as JSON: /api/errors/af04834dff824ecc.
Report an issue: GitHub.