calcom/cal.diy · error · NotFoundException
Deleted link not found
Error message
Deleted link not found
What it means
Thrown by PrivateLinksService.deletePrivateLink when repo.delete returns count === 0, meaning no row matched the (eventTypeId, linkId) pair. This is a clean not-found signal: the delete affected nothing, so the link either never existed, was already deleted, or belongs to a different event type.
Source
Thrown at apps/api/v2/src/platform/event-types-private-links/services/private-links.service.ts:109
usageCount: updated.usageCount ?? 0,
};
return this.outputService.transformToOutput(mapped);
} catch (error) {
if (error instanceof Error) {
if (error.message.includes("not found")) {
throw new NotFoundException(error.message);
}
throw new BadRequestException(error.message);
}
throw new BadRequestException("Failed to update private link");
}
}
async deletePrivateLink(eventTypeId: number, linkId: string): Promise<void> {
try {
const { count } = await this.repo.delete(eventTypeId, linkId);
if (count === 0) {
throw new NotFoundException("Deleted link not found");
}
} catch (error) {
if (error instanceof Error) {
if (error.message.includes("not found")) {
throw new NotFoundException(error.message);
}
throw new BadRequestException(error.message);
}
throw new BadRequestException("Failed to delete private link");
}
}
}
View on GitHub (pinned to 176037d0af)
Solutions
- Treat a 404 on DELETE as success if your operation is idempotent (the link is gone either way).
- Refresh the link list via GET before showing a delete button so the user cannot target a stale linkId.
- Confirm the eventTypeId in the URL path is the same one used when the link was created.
- If you need strict idempotency, catch the 404 and return a no-content success to your caller.
Example fix
// before
await api.delete(`/v2/event-types/${eventTypeId}/private-links/${linkId}`);
// after - treat already-gone as success
try {
await api.delete(`/v2/event-types/${eventTypeId}/private-links/${linkId}`);
} catch (e) {
if (e.response?.status !== 404) throw e;
// link already deleted; idempotent success
} Defensive patterns
Strategy: try-catch
Validate before calling
// Confirm the link exists before DELETE
const links = (await api.get(`/v2/event-types/${eventTypeId}/private-links`)).data ?? [];
if (!links.some((l) => l.id === linkId)) {
// already gone — treat as success
return;
} Type guard
function isPrivateLinkList(v: unknown): v is Array<{ id: string }> {
return Array.isArray(v) && v.every((x) => typeof x === 'object' && x !== null && typeof (x as any).id === 'string');
} Try / catch
try {
await api.delete(`/v2/event-types/${eventTypeId}/private-links/${linkId}`);
} catch (e) {
if (e.response?.status === 404) return; // idempotent success
throw e;
} Prevention
- Make client-side DELETE idempotent: swallow 404 as success.
- Refresh the link list after every delete so the UI cannot re-target a gone link.
- Guard against concurrent deletes with a client-side 'deleting' flag.
When it happens
Trigger: DELETE /v2/event-types/:eventTypeId/private-links/:linkId where the linkId does not exist for that eventTypeId; the link was already deleted in a prior request; the eventTypeId in the path does not own the linkId.
Common situations: Idempotent delete retries (second DELETE after the first succeeded); linkId copied from a different event type; expired links auto-pruned by a background job between the GET and DELETE; frontend caching a stale link list.
Related errors
- Event type with ID=${eventTypeId} does not exist.
- No SelectedCalendar found.
- Event type with id ${eventTypeId} not found
- User with username "${username}" not found
- Event type with id ${eventTypeId} not found
AI-assisted analysis of calcom/cal.diy@176037d0af (2026-08-12).
Data as JSON: /api/errors/e3dcefce6a019f83.
Report an issue: GitHub.