> ## Documentation Index
> Fetch the complete documentation index at: https://www.dynamic.xyz/docs/llms.txt
> Use this file to discover all available pages before exploring further.

# Account conflict resolution

> Handle the case where a user tries to add a credential — an email, phone, social account, or wallet — that already belongs to a different account.

## Prerequisites

Before this page: get a user [signed in](/javascript/building-ui/email-sms-otp-sign-in) and, ideally, [set up](/javascript/building-ui/post-auth-user-setup). Conflicts only arise while a user is authenticated and adding another credential to their account.

## What you'll build

When a signed-in user adds a new credential — verifying another email or phone, connecting a social account, or linking a wallet — that credential is attached to their current account. But it might **already belong to someone else**. This page shows how to detect that conflict and guide the user to a resolution instead of failing silently.

There are three outcomes the SDK surfaces, and each needs different UI:

| Outcome                  | The SDK throws                          | What it means                                                                                                                                                                   |
| ------------------------ | --------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| **Mergeable**            | `MergeAccountsConfirmationError`        | The credential belongs to another account, but the two can be merged into one. You ask the user to confirm, then complete the [merge](/javascript/building-ui/account-merging). |
| **Wallet already taken** | `WalletAlreadyLinkedToAnotherUserError` | The wallet is verified on another account and can't be moved.                                                                                                                   |
| **Can't reassign**       | `LinkCredentialError`                   | The credential is tied to another account and cannot be reassigned or merged.                                                                                                   |

<Note>
  Linking uses the same verification calls you use to sign in — `verifyOTP` for email/phone, the social verification flow, and wallet verification. When a user is already signed in, a successful verification **links** the credential; a conflict throws one of the errors above.
</Note>

## Detecting and routing the conflict

Wrap the verification call and branch on the error type. The three cases map directly to three pieces of UI.

<Tabs>
  <Tab title="TypeScript">
    ```typescript theme={"system"}
    import {
      MergeAccountsConfirmationError,
      WalletAlreadyLinkedToAnotherUserError,
      LinkCredentialError,
    } from '@dynamic-labs-sdk/client';

    // `linkCredential` is your call to the relevant verification function —
    // e.g. verifyOTP({ ... }) for an email/phone, or the wallet verification flow.
    async function addCredential(linkCredential: () => Promise<void>) {
      try {
        await linkCredential();
        // showLinked is your implementation.
        showLinked('Added to your account.');
      } catch (error) {
        if (error instanceof MergeAccountsConfirmationError) {
          // Mergeable: hand off to the merge flow with the surfaced conflicts.
          // startMergeFlow is your implementation — see "Account merging".
          startMergeFlow(error.mergeConflicts);
          return;
        }

        if (error instanceof WalletAlreadyLinkedToAnotherUserError) {
          showConflict('That wallet is already connected to a different account.');
          return;
        }

        if (error instanceof LinkCredentialError) {
          showConflict(
            'That credential already belongs to another account and can\'t be moved.',
          );
          return;
        }

        throw error;
      }
    }
    ```
  </Tab>

  <Tab title="React">
    ```tsx theme={"system"}
    import {
      MergeAccountsConfirmationError,
      WalletAlreadyLinkedToAnotherUserError,
      LinkCredentialError,
    } from '@dynamic-labs-sdk/client';

    function AddCredentialButton() {
      // useLinkCredential is your own TanStack mutation wrapping the verification
      // call you use to add a credential — verifyOtp for email/phone, the social
      // flow, or wallet verification. A successful mutation links the credential;
      // a conflict rejects with one of the errors below, so the routing lives in
      // onError. showLinked / showConflict / startMergeFlow are your implementation.
      const { mutate: linkCredential, isPending } = useLinkCredential({
        onSuccess: () => showLinked('Added to your account.'),
        onError: (error) => {
          if (error instanceof MergeAccountsConfirmationError) {
            // Mergeable: hand off to the merge flow with the surfaced conflicts.
            startMergeFlow(error.mergeConflicts);
            return;
          }

          if (error instanceof WalletAlreadyLinkedToAnotherUserError) {
            showConflict('That wallet is already connected to a different account.');
            return;
          }

          if (error instanceof LinkCredentialError) {
            showConflict(
              "That credential already belongs to another account and can't be moved.",
            );
            return;
          }
        },
      });

      return (
        <button onClick={() => linkCredential()} disabled={isPending}>
          Add credential
        </button>
      );
    }
    ```
  </Tab>
</Tabs>

## Presenting each outcome

**Mergeable (`MergeAccountsConfirmationError`).** This is the only recoverable conflict. The error carries `mergeConflicts` — the fields where the two accounts disagree (for example, both have a display name). Confirm the merge with the user, let them pick a value for each conflicting field, and complete it. The full walkthrough lives in [Account merging](/javascript/building-ui/account-merging).

**Wallet already taken (`WalletAlreadyLinkedToAnotherUserError`).** The wallet is verified on another account, so it can't be linked here. Tell the user plainly and offer an alternative (connect a different wallet, or sign in to the account that owns this one).

**Can't reassign (`LinkCredentialError`).** A hard stop — the credential can't be moved or merged. Keep the user on their current account and suggest using a different credential.

<Tip>
  Show the conflict message next to the input the user just acted on (the email field, the connect-wallet button), not as a full-screen error. The user is signed in and nothing they've done is lost — only the new credential wasn't added.
</Tip>

## Handling errors

| Error                                   | When                                                     | What to do                                                                                                              |
| --------------------------------------- | -------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------- |
| `MergeAccountsConfirmationError`        | Credential belongs to another account that can be merged | Start the [merge flow](/javascript/building-ui/account-merging); read `error.mergeConflicts` for the fields to resolve. |
| `WalletAlreadyLinkedToAnotherUserError` | Wallet is verified on another account                    | Ask the user to connect a different wallet, or sign in to the owning account.                                           |
| `LinkCredentialError`                   | Credential can't be reassigned or merged                 | Keep the current account; suggest a different credential.                                                               |
| `WalletScreeningBlockedError`           | Wallet was blocked by compliance screening               | Handle separately — see [Handling blocked wallets](/javascript/building-ui/blocked-wallet-screening).                   |

## See also

* [Account merging](/javascript/building-ui/account-merging) — resolve a `MergeAccountsConfirmationError` end to end
* [Email & SMS OTP sign-in](/javascript/building-ui/email-sms-otp-sign-in) — the verification calls that also link credentials
* [Handling blocked wallets](/javascript/building-ui/blocked-wallet-screening) — the compliance-screening conflict
