calcom/cal.diy · error · BadRequestException

Booking redirect infinite not allowed.

Error message

Booking redirect infinite not allowed.

What it means

Thrown by checkExistingOooRedirect() when an existing OutOfOfficeEntry is found for the requested time window that would create a redirect cycle. The repository query looks for any entry whose toUserId is the current user and whose time range overlaps or sits inside the new window — i.e. someone is already redirecting TO this user, so this user redirecting onward (or back) risks an infinite booking-redirect chain.

Source

Thrown at apps/api/v2/src/modules/ooo/services/ooo.service.ts:76

    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.");
      }
    }
  }

  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.");
    }

View on GitHub (pinned to 176037d0af)

Solutions

  1. Before creating a redirect, query existing redirects for the window and choose a target who is not already redirecting in that period.
  2. Shorten or move the window so it does not overlap an existing redirect that points back into the chain.
  3. Clear the conflicting redirect (delete the other OOO entry) before setting up the new one, if business rules allow.

Example fix

// before — pick any teammate
const target = teammates[0].userId;
await api.post('/ooo', { start, end, toUserId: target });
// after — exclude targets already in a redirect cycle for this window
const busy = await api.get('/ooo/redirects', { start, end });
const free = teammates.filter(t => !busy.includes(t.userId));
await api.post('/ooo', { start, end, toUserId: free[0].userId });
Defensive patterns

Strategy: try-catch

Validate before calling

async function findCycleFreeTarget(window: { start: string; end: string }, candidates: number[]): Promise<number | undefined> {
  const existing = await api.get('/ooo', { params: window }); // entries that already redirect into this user
  const blocked = new Set(existing.map((e: { toUserId: number; userId: number }) => e.userId));
  return candidates.find(id => !blocked.has(id));
}

Try / catch

try { await api.post('/ooo', body); }
catch (e) {
  if (/redirect infinite/i.test(e.message)) { /* pick a different toUserId or shrink window */ }
  else throw e;
}

Prevention

When it happens

Trigger: User A already has an OOO redirect pointing to User B for a window overlapping the request; now User B (or A) tries to set up a redirect in that same window. Also fires when the target user is already a redirect source in the window (toUserId chain).

Common situations: Two teammates going on vacation and pointing at each other; chaining redirects A→B→C where C redirects back to A; overlapping OOO windows that were created independently and now collide on edit.

Related errors


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