{"record":{"id":"065891f74d024e54","repo":"hcengineering/platform","slug":"phone-number-is-already-used","errorCode":null,"errorMessage":"Phone number is already used","messagePattern":"Phone number is already used","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"services/telegram/pod-telegram/src/platform.ts","lineNumber":29,"sourceCode":"    private readonly storageAdapter: StorageAdapter,\n    private readonly clientMap: Map<string, WorkspaceWorker>,\n    private readonly storage: Collection<UserRecord>\n  ) {}\n\n  async close (): Promise<void> {\n    await Promise.all(\n      [...this.clientMap.values()].map(async (worker) => {\n        await worker.close()\n      })\n    )\n  }\n\n  async addUser (tgUser: TgUser): Promise<void> {\n    const { workspace, phone } = tgUser as any // TODO: FIXME\n    const res = await this.storage.findOne({ phone, workspace })\n\n    if (res !== null) {\n      throw Error('Phone number is already used')\n    }\n\n    let wsWorker = this.clientMap.get(workspace)\n\n    if (wsWorker === undefined) {\n      const [userStorage, lastMsgStorage, channelStorage] = await PlatformWorker.createStorages()\n      wsWorker = await WorkspaceWorker.create(\n        this.ctx,\n        this.storageAdapter,\n        workspace,\n        userStorage,\n        lastMsgStorage,\n        channelStorage\n      )\n      this.clientMap.set(workspace, wsWorker)\n    }\n\n    await wsWorker.addUser(tgUser)","sourceCodeStart":11,"sourceCodeEnd":47,"githubUrl":"https://github.com/hcengineering/platform/blob/63e28dc96483967b2fc21c881b3f1023c1de7718/services/telegram/pod-telegram/src/platform.ts#L11-L47","documentation":"addUser registers a telegram user for a workspace and stores the record keyed by (phone, workspace). If a record with the same phone already exists for that workspace, it throws 'Phone number is already used' to prevent duplicate bindings of one phone within a workspace.","triggerScenarios":"Calling addUser with a TgUser whose phone was previously registered in the same workspace — e.g. re-linking an account, retrying a signup that partially persisted, or two accounts sharing one phone number.","commonSituations":"Users re-installing the bot and signing up again, testing with the same phone across accounts, or a previous registration that crashed after the storage write but before completion.","solutions":["Check for an existing registration (storage.findOne({phone, workspace})) and reuse it instead of throwing.","Remove the existing user (removeUser) before re-adding, or implement an upsert.","Ask the user for a different phone number if the old binding is intentional.","For stale records from crashed signups, clean up the storage record manually then retry."],"exampleFix":"// before\nconst res = await this.storage.findOne({ phone, workspace })\nif (res !== null) {\n  throw Error('Phone number is already used')\n}\n// after\nconst res = await this.storage.findOne({ phone, workspace })\nif (res !== null) {\n  if (res.user === tgUser.user) return // idempotent re-add for same user\n  throw Error('Phone number is already used')\n}","handlingStrategy":"try-catch","validationCode":"const existing = await storage.findOne({ phone, workspace })\nif (existing !== null) console.warn('Phone already registered for workspace; re-add will fail')","typeGuard":null,"tryCatchPattern":"try {\n  await platform.addUser(tgUser)\n} catch (err) {\n  if (err.message === 'Phone number is already used') {\n    console.warn('Phone already bound to workspace; skipping or updating existing user')\n    return\n  }\n  throw err\n}","preventionTips":["Check for an existing (phone, workspace) record before calling addUser.","Make signup idempotent for the same user instead of throwing.","Clean up partial registrations from crashed signups.","Prevent two accounts sharing one phone at the UI level."],"tags":["duplicate","registration","telegram","storage"],"backgroundTag":"duplicate-record-conflict","analyzedSha":"63e28dc96483967b2fc21c881b3f1023c1de7718","analyzedAt":"2026-08-29T15:21:27.377Z","schemaVersion":2},"datasetVersion":"2026-08-29T17:17:51.833Z"}