> ## Documentation Index
> Fetch the complete documentation index at: https://docs.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](https://docs.dynamic.xyz/docs/javascript/building-ui/email-sms-otp-sign-in.md) and, ideally, [set up](https://docs.dynamic.xyz/docs/javascript/building-ui/post-auth-user-setup.md). 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](https://docs.dynamic.xyz/docs/javascript/building-ui/account-merging.md). |
| **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.

## 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.

> [tab] 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] 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>
>   );
> }
> ```

## 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](https://docs.dynamic.xyz/docs/javascript/building-ui/account-merging.md).

**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.

## Handling errors

| Error | When | What to do |
| - | - | - |
| `MergeAccountsConfirmationError` | Credential belongs to another account that can be merged | Start the [merge flow](https://docs.dynamic.xyz/docs/javascript/building-ui/account-merging.md); 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 — inform the user their wallet has been blocked by compliance screening. |

## See also

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


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.