{"record":{"id":"b893102e78f07840","repo":"calcom/cal.diy","slug":"isuserwebhookguard-no-webhook-id-found-in-reques","errorCode":null,"errorMessage":"IsUserWebhookGuard - No webhook id found in request params.","messagePattern":"IsUserWebhookGuard - No webhook id found in request params\\.","errorType":"http","errorClass":"ForbiddenException","httpStatus":403,"severity":"error","filePath":"apps/api/v2/src/modules/webhooks/guards/is-user-webhook-guard.ts","lineNumber":22,"sourceCode":"import { Request } from \"express\";\n\nimport type { Webhook } from \"@calcom/prisma/client\";\n\n@Injectable()\nexport class IsUserWebhookGuard implements CanActivate {\n  constructor(private readonly webhooksService: WebhooksService) {}\n\n  async canActivate(context: ExecutionContext): Promise<boolean> {\n    const request = context.switchToHttp().getRequest<Request & { webhook: Webhook }>();\n    const user = request.user as ApiAuthGuardUser;\n    const webhookId = request.params.webhookId;\n\n    if (!user) {\n      throw new ForbiddenException(\"IsUserWebhookGuard - No user associated with the request.\");\n    }\n\n    if (!webhookId) {\n      throw new ForbiddenException(\"IsUserWebhookGuard - No webhook id found in request params.\");\n    }\n\n    const webhook = await this.webhooksService.getWebhookById(webhookId);\n\n    if (webhook.userId !== user.id && !user.isSystemAdmin) {\n      throw new ForbiddenException(\n        `IsUserWebhookGuard - user with id=(${user.id}) is not the owner of webhook with id=(${webhookId})`\n      );\n    }\n\n    request.webhook = webhook;\n    return true;\n  }\n}\n","sourceCodeStart":4,"sourceCodeEnd":37,"githubUrl":"https://github.com/calcom/cal.diy/blob/176037d0afbe572f870a3c702985e7cd83fe6c0c/apps/api/v2/src/modules/webhooks/guards/is-user-webhook-guard.ts#L4-L37","documentation":"NestJS authorization guard (IsUserWebhookGuard) refuses the request because no webhookId was present in request.params. The guard extracts webhookId from the route param before it can fetch and ownership-check the webhook; a missing param means it cannot proceed safely, so it throws ForbiddenException (HTTP 403). This is a routing/URL-shape failure, not a database miss.","triggerScenarios":"A request reaches a webhook route guarded by IsUserWebhookGuard but the URL does not contain a :webhookId segment, or the param name in the controller route differs from 'webhookId', or the param is an empty string. E.g. calling DELETE /webhooks/ instead of DELETE /webhooks/:webhookId.","commonSituations":"Client built the URL from an undefined/null webhook id; route template typo (e.g. :id instead of :webhookId); a reverse proxy or gateway stripped the path segment; frontend passed an empty string after a failed lookup.","solutions":["Inspect the outgoing request URL — confirm it contains a non-empty :webhookId path segment matching the controller route.","Ensure the client resolves webhookId before constructing the URL (fail fast if it is undefined).","Verify the controller's @Param('webhookId') name matches the route template variable exactly.","Add a client-side assertion that webhookId is a non-empty string before issuing the request."],"exampleFix":"// before\nawait fetch(`/webhooks/${maybeUndefined}`);\n// after\nif (!webhookId) throw new Error('webhookId required');\nawait fetch(`/webhooks/${encodeURIComponent(webhookId)}`);","handlingStrategy":"validation","validationCode":"function assertWebhookIdRoute(webhookId: unknown): string {\n  if (typeof webhookId !== 'string' || webhookId.trim() === '') {\n    throw new Error('webhookId path segment is required');\n  }\n  return webhookId;\n}\n// before fetch:\nassertWebhookIdRoute(webhookId);","typeGuard":"const isNonEmptyString = (v: unknown): v is string =>\n  typeof v === 'string' && v.trim().length > 0;","tryCatchPattern":"try { await api.call(); }\ncatch (e) {\n  if (e.status === 403 && /No webhook id found/.test(e.message)) {\n    // fix the URL and retry with a non-empty webhookId\n  } else throw e;\n}","preventionTips":["Always URL-encode and assert the webhookId before constructing the request.","Keep the controller route param name and @Param name aligned in code review.","Add integration tests that assert 400/404 for missing params rather than 403."],"tags":["nestjs","guard","authorization","routing","webhooks"],"backgroundTag":null,"analyzedSha":"176037d0afbe572f870a3c702985e7cd83fe6c0c","analyzedAt":"2026-08-12T19:12:41.464Z","schemaVersion":2},"datasetVersion":"2026-08-12T23:17:12.415Z"}