calcom/cal.diy · error · ForbiddenException

IsUserWebhookGuard - No webhook id found in request params.

Error message

IsUserWebhookGuard - No webhook id found in request params.

What it means

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.

Source

Thrown at apps/api/v2/src/modules/webhooks/guards/is-user-webhook-guard.ts:22

import { Request } from "express";

import type { Webhook } from "@calcom/prisma/client";

@Injectable()
export class IsUserWebhookGuard implements CanActivate {
  constructor(private readonly webhooksService: WebhooksService) {}

  async canActivate(context: ExecutionContext): Promise<boolean> {
    const request = context.switchToHttp().getRequest<Request & { webhook: Webhook }>();
    const user = request.user as ApiAuthGuardUser;
    const webhookId = request.params.webhookId;

    if (!user) {
      throw new ForbiddenException("IsUserWebhookGuard - No user associated with the request.");
    }

    if (!webhookId) {
      throw new ForbiddenException("IsUserWebhookGuard - No webhook id found in request params.");
    }

    const webhook = await this.webhooksService.getWebhookById(webhookId);

    if (webhook.userId !== user.id && !user.isSystemAdmin) {
      throw new ForbiddenException(
        `IsUserWebhookGuard - user with id=(${user.id}) is not the owner of webhook with id=(${webhookId})`
      );
    }

    request.webhook = webhook;
    return true;
  }
}

View on GitHub (pinned to 176037d0af)

Solutions

  1. Inspect the outgoing request URL — confirm it contains a non-empty :webhookId path segment matching the controller route.
  2. Ensure the client resolves webhookId before constructing the URL (fail fast if it is undefined).
  3. Verify the controller's @Param('webhookId') name matches the route template variable exactly.
  4. Add a client-side assertion that webhookId is a non-empty string before issuing the request.

Example fix

// before
await fetch(`/webhooks/${maybeUndefined}`);
// after
if (!webhookId) throw new Error('webhookId required');
await fetch(`/webhooks/${encodeURIComponent(webhookId)}`);
Defensive patterns

Strategy: validation

Validate before calling

function assertWebhookIdRoute(webhookId: unknown): string {
  if (typeof webhookId !== 'string' || webhookId.trim() === '') {
    throw new Error('webhookId path segment is required');
  }
  return webhookId;
}
// before fetch:
assertWebhookIdRoute(webhookId);

Type guard

const isNonEmptyString = (v: unknown): v is string =>
  typeof v === 'string' && v.trim().length > 0;

Try / catch

try { await api.call(); }
catch (e) {
  if (e.status === 403 && /No webhook id found/.test(e.message)) {
    // fix the URL and retry with a non-empty webhookId
  } else throw e;
}

Prevention

When it happens

Trigger: 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.

Common situations: 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.

Related errors


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