hcengineering/platform · error · Error

Phone number is already used

Error message

Phone number is already used

What it means

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.

Source

Thrown at services/telegram/pod-telegram/src/platform.ts:29

    private readonly storageAdapter: StorageAdapter,
    private readonly clientMap: Map<string, WorkspaceWorker>,
    private readonly storage: Collection<UserRecord>
  ) {}

  async close (): Promise<void> {
    await Promise.all(
      [...this.clientMap.values()].map(async (worker) => {
        await worker.close()
      })
    )
  }

  async addUser (tgUser: TgUser): Promise<void> {
    const { workspace, phone } = tgUser as any // TODO: FIXME
    const res = await this.storage.findOne({ phone, workspace })

    if (res !== null) {
      throw Error('Phone number is already used')
    }

    let wsWorker = this.clientMap.get(workspace)

    if (wsWorker === undefined) {
      const [userStorage, lastMsgStorage, channelStorage] = await PlatformWorker.createStorages()
      wsWorker = await WorkspaceWorker.create(
        this.ctx,
        this.storageAdapter,
        workspace,
        userStorage,
        lastMsgStorage,
        channelStorage
      )
      this.clientMap.set(workspace, wsWorker)
    }

    await wsWorker.addUser(tgUser)

View on GitHub (pinned to 63e28dc964)

Solutions

  1. Check for an existing registration (storage.findOne({phone, workspace})) and reuse it instead of throwing.
  2. Remove the existing user (removeUser) before re-adding, or implement an upsert.
  3. Ask the user for a different phone number if the old binding is intentional.
  4. For stale records from crashed signups, clean up the storage record manually then retry.

Example fix

// before
const res = await this.storage.findOne({ phone, workspace })
if (res !== null) {
  throw Error('Phone number is already used')
}
// after
const res = await this.storage.findOne({ phone, workspace })
if (res !== null) {
  if (res.user === tgUser.user) return // idempotent re-add for same user
  throw Error('Phone number is already used')
}
Defensive patterns

Strategy: try-catch

Validate before calling

const existing = await storage.findOne({ phone, workspace })
if (existing !== null) console.warn('Phone already registered for workspace; re-add will fail')

Try / catch

try {
  await platform.addUser(tgUser)
} catch (err) {
  if (err.message === 'Phone number is already used') {
    console.warn('Phone already bound to workspace; skipping or updating existing user')
    return
  }
  throw err
}

Prevention

When it happens

Trigger: 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.

Common situations: 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.

Related errors


AI-assisted analysis of hcengineering/platform@63e28dc964 (2026-08-29). Data as JSON: /api/errors/065891f74d024e54. Report an issue: GitHub.