{"record":{"id":"f0e54680adf9a1f9","repo":"we-promise/sure","slug":"brexitem-accountflow-accountalreadylinkederror","errorCode":null,"errorMessage":"BrexItem::AccountFlow::AccountAlreadyLinkedError","messagePattern":"BrexItem::AccountFlow::AccountAlreadyLinkedError","errorType":"exception","errorClass":"BrexItem::AccountFlow::AccountAlreadyLinkedError","httpStatus":null,"severity":"warning","filePath":"app/models/brex_item/account_flow.rb","lineNumber":215,"sourceCode":"    LinkAccountsResult.new(\n      created_accounts: created_accounts,\n      already_linked_names: already_linked_names,\n      invalid_account_ids: invalid_account_ids\n    )\n  end\n\n  def link_existing_account!(account:, brex_account_id:)\n    account_data = indexed_accounts[brex_account_id.to_s]\n    raise AccountNotFoundError unless account_data\n\n    account_name = BrexAccount.name_for(account_data)\n    raise InvalidAccountNameError if account_name.blank?\n\n    brex_account = nil\n\n    ActiveRecord::Base.transaction do\n      brex_account = upsert_brex_account!(brex_account_id, account_data)\n      raise AccountAlreadyLinkedError if brex_account.account_provider.present?\n\n      AccountProvider.create!(account: account, provider: brex_account)\n    end\n\n    brex_item.sync_later\n\n    brex_account\n  end\n\n  private\n\n    def selection_error_payload\n      if brex_item_id.present?\n        return {\n          success: false,\n          error: \"select_connection\",\n          error_message: I18n.t(\"brex_items.select_accounts.select_connection\"),\n          has_accounts: nil","sourceCodeStart":197,"sourceCodeEnd":233,"githubUrl":"https://github.com/we-promise/sure/blob/e69894adb92547273377398c15f45c979cd9416a/app/models/brex_item/account_flow.rb#L197-L233","documentation":"Raised by BrexItem::AccountFlow#link_existing_account! as AccountAlreadyLinkedError when the freshly upserted BrexAccount record already has an account_provider — i.e. that Brex account is already linked to a Maybe account. The raise happens inside ActiveRecord::Base.transaction, so the new AccountProvider creation rolls back and no partial link survives.","triggerScenarios":"link_existing_account! runs after the same Brex account was already linked elsewhere: a stale picker showed it as available (the unfiltered accounts list includes linked ones), two tabs/users race to link it, or a retry resubmits after a first successful link (app/models/brex_item/account_flow.rb:213-215).","commonSituations":"Double-clicked submit buttons; back-button resubmission; UI list built from all provider accounts instead of unlinked_available_accounts; one Brex account intentionally or accidentally shared between two Maybe accounts.","solutions":["Drive the picker from select_existing_account_result (built on unlinked_available_accounts), which already filters linked accounts, so the option never appears.","Rescue AccountAlreadyLinkedError and show the 'provider account already linked' alert — link_existing_account_result already maps this if you use the public wrapper.","Unlink the existing account first (Unlinking concern) if you genuinely want to re-point it.","Make the submit action idempotent (disable after click, POST-once tokens) to kill double-submit races."],"exampleFix":"# before\nflow.link_existing_account!(account: acct, brex_account_id: id)\n\n# after — use the result wrapper that handles all link failures\nresult = flow.link_existing_account_result(account: acct, brex_account_id: id)\nredirect_to accounts_path, result.flash_type => result.message\n# or, calling the bang method directly:\nbegin\n  flow.link_existing_account!(account: acct, brex_account_id: id)\nrescue BrexItem::AccountFlow::AccountAlreadyLinkedError\n  redirect_to accounts_path, alert: \"That Brex account is already linked.\"\nend","handlingStrategy":"validation","validationCode":"# Build pickers only from accounts not yet linked\nresult = flow.select_existing_account_result(accountable_type: \"CreditCard\") # filters via unlinked_available_accounts\nreturn if result.available_accounts.empty?","typeGuard":null,"tryCatchPattern":"begin\n  flow.link_existing_account!(account: account, brex_account_id: id)\nrescue BrexItem::AccountFlow::AccountAlreadyLinkedError\n  redirect_to accounts_path, alert: \"That Brex account is already linked to another account.\"\nend","preventionTips":["Render linkable accounts from select_existing_account_result (backed by unlinked_available_accounts) so linked ones never appear.","Make submit buttons idempotent (disable-on-click, one-time tokens) to prevent double-submit races.","Unlink the existing account first when intentionally re-pointing a Brex account to a new Maybe account."],"tags":["brex","account-linking","duplicate","uniqueness"],"backgroundTag":"account-already-linked","analyzedSha":"e69894adb92547273377398c15f45c979cd9416a","analyzedAt":"2026-08-21T18:22:41.165Z","schemaVersion":2},"datasetVersion":"2026-08-21T23:17:16.201Z"}