{"record":{"id":"b1a883d20e97d8f8","repo":"calcom/cal.diy","slug":"failed-to-delete-private-link","errorCode":null,"errorMessage":"Failed to delete private link","messagePattern":"Failed to delete private link","errorType":"http","errorClass":"BadRequestException","httpStatus":400,"severity":"critical","filePath":"apps/api/v2/src/platform/event-types-private-links/services/private-links.service.ts","lineNumber":118,"sourceCode":"      }\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":100,"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#L100-L122","documentation":"Fallback BadRequestException thrown by PrivateLinksService.deletePrivateLink when the caught value is not an Error instance. This defensive branch covers non-Error throws (strings, plain objects) from anywhere in the delete pipeline. The generic message hides the original cause, making it a debugging dead-end without instrumentation.","triggerScenarios":"A downstream method (repo.delete or Prisma internals) throwing a non-Error primitive; a Promise rejection with a raw value; an older dependency that throws strings; an internal assertion that rejects with a plain object.","commonSituations":"Custom repository code that does `throw 'delete failed'`; a mocked test double that rejects with a string; a transitive dependency regression after `yarn upgrade`. Because the message is generic, users cannot tell whether the link existed.","solutions":["Search the codebase for `throw` of non-Error values and convert them to `throw new Error(...)`.","Add structured logging in the catch block to capture the raw value and its type before the fallback fires.","Wrap third-party calls so they always reject with Error instances.","Consider this a defect to file against the service: a 400 with 'Failed to delete private link' is not actionable for a client."],"exampleFix":"// before (downstream)\nif (!conn) throw 'no db connection';\n// after\nif (!conn) throw new Error('no db connection');","handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"try {\n  await api.delete(url);\n} catch (e) {\n  if (e.response?.status === 400 && e.response?.data?.message === 'Failed to delete private link') {\n    // opaque server defect; retry once then escalate\n  } else throw e;\n}","preventionTips":["Report to the server team — this fallback hides the real cause.","Ensure your test doubles (mocks) reject with Error instances, not strings.","Pin dependency versions to avoid transitive regressions in throw shapes."],"tags":["nestjs","bad-request","defensive-catch","private-links","error-handling"],"backgroundTag":null,"analyzedSha":"176037d0afbe572f870a3c702985e7cd83fe6c0c","analyzedAt":"2026-08-12T19:12:41.464Z","schemaVersion":2},"datasetVersion":"2026-08-12T23:17:12.415Z"}