calcom/cal.diy · error · BadRequestException
Failed to create private link
Error message
Failed to create private link
What it means
The fallback in PrivateLinksService.createPrivateLink's catch: if the thrown value is NOT an instance of Error (e.g. a Prisma error object with a different prototype, a non-Error thrown by a dependency, or a plain object), BadRequestException('Failed to create private link') is raised as a generic message. This is the lossy path: the original cause is dropped from the response.
Source
Thrown at apps/api/v2/src/platform/event-types-private-links/services/private-links.service.ts:46
link: generateHashedLink(userId),
expiresAt: transformedInput.expiresAt ?? null,
maxUsageCount: transformedInput.maxUsageCount ?? null,
});
const mapped: PrivateLinkData = {
id: created.link,
eventTypeId,
isExpired: isLinkExpired(created as any),
bookingUrl: `${process.env.NEXT_PUBLIC_WEBAPP_URL || "https://cal.com"}/d/${created.link}`,
expiresAt: created.expiresAt ?? null,
maxUsageCount: (created as any).maxUsageCount ?? null,
usageCount: (created as any).usageCount ?? 0,
};
return this.outputService.transformToOutput(mapped);
} catch (error) {
if (error instanceof Error) {
throw new BadRequestException(error.message);
}
throw new BadRequestException("Failed to create private link");
}
}
async getPrivateLinks(eventTypeId: number): Promise<PrivateLinkOutput[]> {
try {
const links = await this.repo.listByEventTypeId(eventTypeId);
const mapped: PrivateLinkData[] = links.map((l) => ({
id: l.link,
eventTypeId,
isExpired: isLinkExpired(l as any),
bookingUrl: `${process.env.NEXT_PUBLIC_WEBAPP_URL || "https://cal.com"}/d/${l.link}`,
expiresAt: l.expiresAt ?? null,
maxUsageCount: l.maxUsageCount ?? null,
usageCount: l.usageCount ?? 0,
}));
return this.outputService.transformArrayToOutput(mapped);
} catch (error) {
if (error instanceof Error) {View on GitHub (pinned to 176037d0af)
Solutions
- Inspect the API server logs: the generic response hides the cause but the logger/stack should still record it.
- If reproducible, add a temporary console.error of the caught value to see its shape, then handle it explicitly.
- Verify the input passes transformCreateInput before posting.
Defensive patterns
Strategy: try-catch
Try / catch
try {
await privateLinksService.createPrivateLink(eventTypeId, userId, input);
} catch (e) {
if (e instanceof BadRequestException && e.message === 'Failed to create private link') {
// generic fallback; inspect server logs for the non-Error cause
} else throw e;
} Prevention
- Pre-validate input so the only remaining failures are DB-side and rare.
- Log the raw caught value server-side so non-Error rejections are diagnosable.
- Treat the generic message as a server fault and retry once after checking logs.
When it happens
Trigger: A Prisma PrismaClientKnownRequestError that on some code paths isn't an Error instance; a dependency throwing a non-Error value; a serialization failure inside the mapping block (e.g. created.link undefined -> bookingUrl malformed); any non-Error rejection from generateHashedLink or repo.create.
Common situations: DB outage mid-create; unique-constraint violation surfaced as a non-Error; a refactor that changed what repo.create throws; integration tests throwing plain objects.
Related errors
- ${error.message}
- Failed to get private links
- Could not add ICS feeds, try using private ics feed.
- Either expiresAt or maxUsageCount must be provided
- Provide only one of expiresAt or maxUsageCount
AI-assisted analysis of calcom/cal.diy@176037d0af (2026-08-12).
Data as JSON: /api/errors/008cc01a56bbbfd5.
Report an issue: GitHub.