{"record":{"id":"05ef78becc17544c","repo":"yikart/AiToEarn","slug":"responsecode-channelaccountalreadyconnectedtoanoth","errorCode":"ResponseCode.ChannelAccountAlreadyConnectedToAnotherUser","errorMessage":"ChannelAccountAlreadyConnectedToAnotherUser","messagePattern":"ChannelAccountAlreadyConnectedToAnotherUser","errorType":"error_code","errorClass":"AppException","httpStatus":null,"severity":"error","filePath":"project/aitoearn-backend/apps/aitoearn-server/src/core/channels/accounts/account.service.ts","lineNumber":446,"sourceCode":"    identity: AccountIdentity,\n    accountData: Partial<Account>,\n    userId: string,\n  ): Promise<Account> {\n    let account = await this.accountRepository.getByIdentity(identity)\n    let created = false\n    if (!account) {\n      account = await this.accountRepository.createByIdentity(identity, accountData)\n      created = true\n    }\n\n    if (!account) {\n      throw new AppException(ResponseCode.AccountCreateFailed)\n    }\n    if (!created && (account.userId === userId || !account.userId)) {\n      account = await this.accountRepository.updateByIdentity(identity, accountData) ?? account\n    }\n    if (account.userId !== userId) {\n      throw new AppException(ResponseCode.ChannelAccountAlreadyConnectedToAnotherUser)\n    }\n\n    return account\n  }\n\n  private async emitAccountConnected(userId: string, account: Account): Promise<void> {\n    await this.eventStream.emit(\n      EventStream.Channels,\n      EventTopic.ChannelsAccountConnected,\n      { userId, accountId: account.id, platform: account.type },\n      { source: 'account-service' },\n    )\n  }\n\n  private async normalizeCreateInput(data: AccountCreateInput): Promise<NormalizedAccountCreateInput> {\n    if (data.type === AccountType.WeChatChannels) {\n      return this.normalizeWeChatChannelsCreateInput(data)\n    }","sourceCodeStart":428,"sourceCodeEnd":464,"githubUrl":"https://github.com/yikart/AiToEarn/blob/d3aa8bea5b146a8675607cf0144d891aad3e9683/project/aitoearn-backend/apps/aitoearn-server/src/core/channels/accounts/account.service.ts#L428-L464","documentation":"After loading/creating the account, saveWritableAccount checks ownership: if the account belongs to a different userId, it throws ChannelAccountAlreadyConnectedToAnotherUser. The channel identity (platform uid) is already bound to another AiToEarn user, so the current user cannot claim it.","triggerScenarios":"Calling createPluginAccount or createRelayAccountRecord with an account identity (platform + uid) whose stored account.userId differs from the requesting userId and the account already has an owner (created === false, account.userId set and different).","commonSituations":"Two team members connecting the same social media account; reconnecting after switching AiToEarn accounts without disconnecting first; test/staging accounts already claimed by another user.","solutions":["Disconnect the channel account from the other user first (delete/unbind it), then reconnect.","Log in as the user who owns the connection, or have that user release it.","Use a different platform account for this user.","If ownership transfer is required, use an admin flow to reassign account.userId rather than forcing the create call."],"exampleFix":"// before\nPOST /channels/accounts { platform: 'twitter', uid: '123' } // bound to user A\n// after\nDELETE /channels/accounts/:id (as user A) then POST the same create as user B","handlingStrategy":"try-catch","validationCode":null,"typeGuard":"function isAlreadyConnected(e: unknown): boolean {\n  return e instanceof AppException && e.code === ResponseCode.ChannelAccountAlreadyConnectedToAnotherUser\n}","tryCatchPattern":"try {\n  await accountService.createPluginAccount(userId, identity, data)\n} catch (e) {\n  if (e instanceof AppException && e.code === ResponseCode.ChannelAccountAlreadyConnectedToAnotherUser) {\n    // surface UI message: 'This channel account is already linked to another user'\n  } else throw e\n}","preventionTips":["Check ownership of an existing identity before attempting to claim it.","Provide a disconnect/unbind flow and instruct users to release accounts first.","Avoid sharing one social media account across multiple AiToEarn users.","Implement an admin ownership-transfer flow for legitimate reassignment."],"tags":["authorization","channel-account","conflict"],"backgroundTag":"account-already-connected","analyzedSha":"d3aa8bea5b146a8675607cf0144d891aad3e9683","analyzedAt":"2026-08-31T14:19:24.185Z","schemaVersion":2},"datasetVersion":"2026-08-31T19:17:28.585Z"}