{"record":{"id":"d66accd6189b8453","repo":"calcom/cal.diy","slug":"no-user-id-found-in-request-params","errorCode":null,"errorMessage":"No user id found in request params.","messagePattern":"No user id found in request params\\.","errorType":"exception","errorClass":"ForbiddenException","httpStatus":403,"severity":"critical","filePath":"apps/api/v2/src/modules/ooo/guards/is-user-ooo.ts","lineNumber":15,"sourceCode":"import { UserOOORepository } from \"@/modules/ooo/repositories/ooo.repository\";\nimport { Injectable, CanActivate, ExecutionContext, ForbiddenException } from \"@nestjs/common\";\nimport { Request } from \"express\";\n\n@Injectable()\nexport class IsUserOOO implements CanActivate {\n  constructor(private oooRepo: UserOOORepository) {}\n\n  async canActivate(context: ExecutionContext): Promise<boolean> {\n    const request = context.switchToHttp().getRequest<Request>();\n    const oooId: string = request.params.oooId;\n    const userId: string = request.params.userId;\n\n    if (!userId) {\n      throw new ForbiddenException(\"No user id found in request params.\");\n    }\n\n    if (!oooId) {\n      throw new ForbiddenException(\"No ooo entry id found in request params.\");\n    }\n\n    const ooo = await this.oooRepo.getUserOOOByIdAndUserId(Number(oooId), Number(userId));\n\n    if (ooo) {\n      return true;\n    }\n\n    throw new ForbiddenException(\"This OOO entry does not belong to this user.\");\n  }\n}\n","sourceCodeStart":1,"sourceCodeEnd":31,"githubUrl":"https://github.com/calcom/cal.diy/blob/176037d0afbe572f870a3c702985e7cd83fe6c0c/apps/api/v2/src/modules/ooo/guards/is-user-ooo.ts#L1-L31","documentation":"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).","triggerScenarios":"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.","commonSituations":"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.","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."],"exampleFix":"// before\n@Controller('ooo')\n@UseGuards(IsUserOOO)\nexport class OOOController {\n  @Patch(':oooId')        // no :userId — guard throws\n  update() { ... }\n}\n\n// after\n@Controller('users/:userId/ooo')\n@UseGuards(IsUserOOO)\nexport class OOOController {\n  @Patch(':oooId')\n  update() { ... }\n}","handlingStrategy":"validation","validationCode":"// Server-side: assert the route exposes :userId before applying IsUserOOO\nfunction assertRouteHasUserId(path: string) {\n  if (!/:userId(\\b|\\?|$|\\()/.test(path)) {\n    throw new Error(`Route '${path}' uses IsUserOOO but has no :userId param`);\n  }\n}","typeGuard":"function requestHasUserId(req: { params?: Record<string, unknown> }): req is { params: { userId: string } } {\n  return typeof req.params?.userId === 'string' && (req.params as any).userId.length > 0;\n}","tryCatchPattern":"// Routing bug — fix the route, do not catch at runtime.","preventionTips":["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."],"tags":["nestjs","guard","routing","ooo","configuration","server-bug"],"backgroundTag":null,"analyzedSha":"176037d0afbe572f870a3c702985e7cd83fe6c0c","analyzedAt":"2026-08-12T19:12:41.464Z","schemaVersion":2},"datasetVersion":"2026-08-12T23:17:12.415Z"}