calcom/cal.diy · critical · ForbiddenException
No user id found in request params.
Error message
No user id found in request params.
What it means
Thrown by the IsUserOOO guard (NestJS CanActivate) when request.params.userId is falsy. The guard protects out-of-office routes that are scoped by user; it expects a :userId route param. An absent param indicates a routing misconfiguration on the server, not bad end-user input. ForbiddenException (HTTP 403).
Source
Thrown at apps/api/v2/src/modules/ooo/guards/is-user-ooo.ts:15
import { UserOOORepository } from "@/modules/ooo/repositories/ooo.repository";
import { Injectable, CanActivate, ExecutionContext, ForbiddenException } from "@nestjs/common";
import { Request } from "express";
@Injectable()
export class IsUserOOO implements CanActivate {
constructor(private oooRepo: UserOOORepository) {}
async canActivate(context: ExecutionContext): Promise<boolean> {
const request = context.switchToHttp().getRequest<Request>();
const oooId: string = request.params.oooId;
const userId: string = request.params.userId;
if (!userId) {
throw new ForbiddenException("No user id found in request params.");
}
if (!oooId) {
throw new ForbiddenException("No ooo entry id found in request params.");
}
const ooo = await this.oooRepo.getUserOOOByIdAndUserId(Number(oooId), Number(userId));
if (ooo) {
return true;
}
throw new ForbiddenException("This OOO entry does not belong to this user.");
}
}
View on GitHub (pinned to 176037d0af)
Solutions
- Ensure every OOO route guarded by IsUserOOO includes :userId in its path.
- In tests, mock request.params = { userId: '<id>', oooId: '<id>' } before invoking the guard.
- Grep the OOO controller to confirm :userId is present on all guarded routes.
- Add a route-level integration test that asserts the param is wired.
Example fix
// before
@Controller('ooo')
@UseGuards(IsUserOOO)
export class OOOController {
@Patch(':oooId') // no :userId — guard throws
update() { ... }
}
// after
@Controller('users/:userId/ooo')
@UseGuards(IsUserOOO)
export class OOOController {
@Patch(':oooId')
update() { ... }
} Defensive patterns
Strategy: validation
Validate before calling
// Server-side: assert the route exposes :userId before applying IsUserOOO
function assertRouteHasUserId(path: string) {
if (!/:userId(\b|\?|$|\()/.test(path)) {
throw new Error(`Route '${path}' uses IsUserOOO but has no :userId param`);
}
} Type guard
function requestHasUserId(req: { params?: Record<string, unknown> }): req is { params: { userId: string } } {
return typeof req.params?.userId === 'string' && (req.params as any).userId.length > 0;
} Try / catch
// Routing bug — fix the route, do not catch at runtime.
Prevention
- Keep :userId in the path of every IsUserOOO-guarded route.
- Mock request.params.userId in guard unit tests.
- Add integration tests covering each guarded OOO route.
When it happens
Trigger: An OOO controller route guarded by IsUserOOO is mounted without a :userId segment in its path, or the request reaches the handler via a path that doesn't populate the param. Reproducible only by misconfigured routing or a test that omits the param.
Common situations: Refactoring OOO routes and dropping :userId; a test invoking the guard with an unpopulated params object; mounting the controller under a prefix that doesn't carry :userId.
Related errors
- No ooo entry id found in request params.
- OAuthClientGuard - No OAuth client associated with the reque
- IsUserWebhookGuard - No webhook id found in request params.
- EventTypeOwnershipGuard - No user associated with the reques
- Missing eventTypeId param.
AI-assisted analysis of calcom/cal.diy@176037d0af (2026-08-12).
Data as JSON: /api/errors/d66accd6189b8453.
Report an issue: GitHub.