{"record":{"id":"e3dcefce6a019f83","repo":"calcom/cal.diy","slug":"deleted-link-not-found","errorCode":null,"errorMessage":"Deleted link not found","messagePattern":"Deleted link not found","errorType":"http","errorClass":"NotFoundException","httpStatus":404,"severity":"error","filePath":"apps/api/v2/src/platform/event-types-private-links/services/private-links.service.ts","lineNumber":109,"sourceCode":"        usageCount: updated.usageCount ?? 0,\n      };\n      return this.outputService.transformToOutput(mapped);\n    } catch (error) {\n      if (error instanceof Error) {\n        if (error.message.includes(\"not found\")) {\n          throw new NotFoundException(error.message);\n        }\n        throw new BadRequestException(error.message);\n      }\n      throw new BadRequestException(\"Failed to update private link\");\n    }\n  }\n\n  async deletePrivateLink(eventTypeId: number, linkId: string): Promise<void> {\n    try {\n      const { count } = await this.repo.delete(eventTypeId, linkId);\n      if (count === 0) {\n        throw new NotFoundException(\"Deleted link not found\");\n      }\n    } catch (error) {\n      if (error instanceof Error) {\n        if (error.message.includes(\"not found\")) {\n          throw new NotFoundException(error.message);\n        }\n        throw new BadRequestException(error.message);\n      }\n      throw new BadRequestException(\"Failed to delete private link\");\n    }\n  }\n}\n","sourceCodeStart":91,"sourceCodeEnd":122,"githubUrl":"https://github.com/calcom/cal.diy/blob/176037d0afbe572f870a3c702985e7cd83fe6c0c/apps/api/v2/src/platform/event-types-private-links/services/private-links.service.ts#L91-L122","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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."],"exampleFix":"// before\nawait api.delete(`/v2/event-types/${eventTypeId}/private-links/${linkId}`);\n// after - treat already-gone as success\ntry {\n  await api.delete(`/v2/event-types/${eventTypeId}/private-links/${linkId}`);\n} catch (e) {\n  if (e.response?.status !== 404) throw e;\n  // link already deleted; idempotent success\n}","handlingStrategy":"try-catch","validationCode":"// Confirm the link exists before DELETE\nconst links = (await api.get(`/v2/event-types/${eventTypeId}/private-links`)).data ?? [];\nif (!links.some((l) => l.id === linkId)) {\n  // already gone — treat as success\n  return;\n}","typeGuard":"function isPrivateLinkList(v: unknown): v is Array<{ id: string }> {\n  return Array.isArray(v) && v.every((x) => typeof x === 'object' && x !== null && typeof (x as any).id === 'string');\n}","tryCatchPattern":"try {\n  await api.delete(`/v2/event-types/${eventTypeId}/private-links/${linkId}`);\n} catch (e) {\n  if (e.response?.status === 404) return; // idempotent success\n  throw e;\n}","preventionTips":["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."],"tags":["nestjs","not-found","private-links","idempotency","rest-api"],"backgroundTag":null,"analyzedSha":"176037d0afbe572f870a3c702985e7cd83fe6c0c","analyzedAt":"2026-08-12T19:12:41.464Z","schemaVersion":2},"datasetVersion":"2026-08-12T23:17:12.415Z"}