Overview

This guide provides solutions to common issues you might encounter while using @turnkey/react-wallet-kit. If you run into any problems, check this section first for potential fixes.

Handling errors with onError

Before we begin, let’s attach an onError callback function to the TurnkeyProvider. Any errors that occur during the execution of functions or initialization will be passed into this callback. This will help you debug issues more effectively.
import { TurnkeyProvider } from "@turnkey/react-wallet-kit";

function App() {
  const turnkeyConfig = {
    //... your existing configuration
  };

  return (
    <TurnkeyProvider
      config={turnkeyConfig}
      callbacks={{
        onError: (error) => {
          // You can also show a user-friendly message, toast or perform other actions here
          console.error("Error:", error);

          // Optionally, you can parse the error to get individual details
          console.error("Error details:", {
            message: error?.message,
            code: error?.code,
            cause: error?.cause,
            name: error?.name,
            stack: error?.stack,
          });
        },
      }}
    >
      {children}
    </TurnkeyProvider>
  );
}

Common issues

There are a few common issues that developers or end-users may encounter when using @turnkey/react-wallet-kit. Here are some of them along with potential solutions:

1. Turnkey SDK failed to initialize

Turnkey SDK Failed to Initialize

Problem

This error shows up when the SDK fails to initialize properly. The initialization process includes a series of network requests that must be made to Turnkey so your configuration must be correct before you launch your app. This issue can happen for several reasons, such as:
  • Missing or incorrect authProxyConfigId or organizationId in the TurnkeyProvider config.
  • Network issues preventing the SDK from reaching Turnkey’s servers.
  • Incorrectly configured apiBaseUrl or authProxyUrl.
  • Auth proxy not being enabled in the Turnkey Dashboard.
You can see the full error by handling it through the onError callback in the TurnkeyProvider as shown above.

Solution

Make sure you have the correct authProxyConfigId and organizationId in your TurnkeyProvider config. You can find these values in the Turnkey Dashboard.
const turnkeyConfig = {
  authProxyConfigId: process.env.NEXT_PUBLIC_AUTH_PROXY_CONFIG_ID || "",
  organizationId: process.env.NEXT_PUBLIC_ORGANIZATION_ID || "",
  // other configurations...
};
If you are using environment variables, ensure they are correctly set up in your .env file or environment configuration. You can also log these values to the console to verify they are being set correctly.
console.log(
  "Auth Proxy Config ID:",
  process.env.NEXT_PUBLIC_AUTH_PROXY_CONFIG_ID
);
console.log("Organization ID:", process.env.NEXT_PUBLIC_ORGANIZATION_ID);
If you are using Turnkey’s Auth Proxy, ensure it is enabled in the Turnkey Dashboard under the Wallet Kit section. You can also check the Getting Started guide for more details on setting up the Auth Poxy. If you decide to use your own authentication setup with a backend, you can simply omit the authProxyConfigId from the TurnkeyProvider config. This will disable the Turnkey auth proxy and allow you to use your own authentication flow. Note that the Log in or sign up modal will not be available in this case, and you will need to implement your own authentication flow.

2. Proxy not enabled

Proxy not enabled

Problem

This error indicates that you are trying to use the Log in or sign up modal without using Turnkey’s auth proxy. The authProxyConfigId is required to use the Turnkey authentication flow.

Solution

To resolve this issue, you need to enable the Auth Proxy in the Turnkey Dashboard under the Wallet Kit section. Once enabled, you will receive an authProxyConfigId that you can use in your TurnkeyProvider config. Pass this authProxyConfigId to the TurnkeyProvider config to enable the authentication flow.
const turnkeyConfig = {
  authProxyConfigId: process.env.NEXT_PUBLIC_AUTH_PROXY_CONFIG_ID || "",
  organizationId: process.env.NEXT_PUBLIC_ORGANIZATION_ID || "",
  // other configurations...
};
If you prefer to use your own authentication flow, you can simply omit the authProxyConfigId from the TurnkeyProvider config. This will disable the Turnkey Auth Proxy and allow you to use your own authentication flow. Note that the Log in or sign up modal will not be available in this case, and you will need to implement your own authentication flow.

3. Turnkey styles are missing

Turnkey styles are missing

Problem

This error indicates that the Turnkey styles are not being applied to the UI components. This can happen if you forget to import the styles in your main application file or if the styles are being modified by other CSS rules in your application.

Solution

Make sure to import the Turnkey styles in your main application file (e.g., app/layout.tsx in Next.js). You can do this by adding the following line at the top of your file:
import "@turnkey/react-wallet-kit/styles.css";
If you’re using Tailwind CSS v3, please refer to the Tailwind v3 error below for specific instructions on how to import the styles correctly. If you are still running into the error but your styles are imported correctly, you can supress the error by adding supressMissingStylesError: true to the ui object in the TurnkeyProvider config. This will disable the styles check.
const turnkeyConfig = {
  //... your existing configuration
  ui: {
    suppressMissingStylesError: true, // Disable styles check. Only do this if you are sure that the styles are being applied correctly.
  },
};

4. Event handlers cannot be passed to Client Component props

Event handlers cannot be passed to Client Component props

Problem

This error occurs when you try to pass in a callback into the TurnkeyProvider but you’re using the TurnkeyProvider in a server component. In Next.js, components default to server components, which means they cannot have event handlers or state.

Solution

To resolve this issue, you need to ensure that the TurnkeyProvider is used in a client component. You can do this by adding "use client"; at the top of your file. This will make the component a client component and allow you to pass in event handlers.
"use client";
import { TurnkeyProvider } from "@turnkey/react-wallet-kit";

function App() {
  const turnkeyConfig = {
    //... your existing configuration
  };

  return (
    <TurnkeyProvider
      config={turnkeyConfig}
      callbacks={{
        onError: (error) => console.error("Turnkey error:", error),
      }}
    >
      {children}
    </TurnkeyProvider>
  );
}

5. No active session or token available

No active session or token available

Problem

This error occurs when you try to use functions that require an authenticated user, such as handleSignMessage, without having an active session. This can happen if the user is not logged in or if the session has expired.

Solution

To resolve this issue, ensure that the user is authenticated before calling functions that require an active session. You can check the authState variable from the useTurnkey hook to determine if the user is authenticated.
import { useTurnkey, AuthState } from "@turnkey/react-wallet-kit";

function AuthStatus() {
  const { authState, user, handleLogin } = useTurnkey();

  return (
    <div>
      {authState === AuthState.Unauthenticated ? (
        <p>Welcome back, {user?.userName}!</p>
      ) : (
        <button onClick={handleLogin}>Log in</button>
      )}
    </div>
  );
}
You can allow the session to automatically refresh by enabling the autoRefreshSession option in the TurnkeyProvider config. This will ensure that the session is refreshed before it expires, keeping the user authenticated.
const turnkeyConfig = {
  //... your existing configuration
  auth: {
    //... your existing auth configuration
    autoRefreshSession: true, // Enable automatic session refresh
  },
};
You can know when a session expires by using the onSessionExpired callback in the TurnkeyProvider. This will allow you to handle session expiration gracefully, such as prompting the user to log in again.
<TurnkeyProvider
  config={turnkeyConfig}
  callbacks={{
    onSessionExpired: () => {
      console.log("Session expired. Please log in again.");
      // Optionally, you can redirect the user to the login page or show a modal
    },
  }}
>
  {children}
</TurnkeyProvider>

6. @layer utilities is used but no matching @tailwind utilities directive is present (Tailwind V3 Error)

Tailwind utilities error

Problem

This error occurs after importing the Turnkey styles in a Tailwind CSS project using Tailwind CSS v3. @turnkey/react-wallet-kit is built with Tailwind CSS v4 under the hood, and exports the styles into a regular CSS file for importing into any project. However, if you are using Tailwind CSS v3, you may encounter this error because Tailwind CSS v3 uses different syntax for CSS directives. Note that this error does not occur in Tailwind CSS v4 projects or when Tailwind CSS is not installed at all.

Solution

We recommend upgrading to Tailwind CSS v4 since this is currently the latest version. You can use the official Tailwind CSS upgrade guide to help you with the upgrade process. If you cannot upgrade to Tailwind CSS v4, you can follow these steps to resolve the issue:
1

Install postcss-import

Install postcss-import if you haven’t already:
npm install -D postcss-import
2

Add postcss-import to your PostCSS config

Add postcss-import to your postcss.config.mjs (or equivalent) file:
/** @type {import('postcss-load-config').Config} */
const config = {
  plugins: {
    tailwindcss: {},
    "postcss-import": {}, // Add postcss-import here
  },
};

export default config;
3

Import Turnkey styles in your main CSS file

Import the Turnkey styles in your main CSS file (e.g., styles/globals.css):We usually recommend importing the styles in your main application file (e.g., app/layout.tsx in Next.js) however, if you’re using Tailwind CSS v3, you can’t do this. Please remove the import if you already have it in your main application file.For Tailwind CSS v3, you need to import the Turnkey styles in your main CSS file (e.g., styles/globals.css) by pointing the import to @turnkey/react-wallet-kit/dist/styles.css file:
@import "@turnkey/react-wallet-kit/dist/styles.css";

@tailwind base;
@tailwind components;
@tailwind utilities;
The Turnkey styles must be imported before the Tailwind directives to ensure that the styles are applied correctly. You also must point to the dist directory to properly retrieve the styles (@turnkey/react-wallet-kit/dist/styles.css instead of @turnkey/react-wallet-kit/styles.css).

7. Radix UI overlapping portals

Radix UI overlapping portals

Problem

This issue occurs when using certain Radix UI components (e.g., Dialog, DropdownMenu, etc.) in the same application as @turnkey/react-wallet-kit. Radix UI uses portals to render components outside of the main DOM hierarchy, which can cause conflicts when trying to open a Turnkey modal while a Radix UI component is also open. You may notice that the Turnkey modal becomes unresponsive or that the Radix UI component remains open and blocks interaction with the Turnkey modal.

Solution

We recommend avoiding using portal-based components from Radix UI (or similar libraries that use portals) while Turnkey’s modals are open. You can also try switching to headless-ui components since Turnkey’s modals are built with headless-ui under the hood. If you cannot avoid using Radix UI components, you can try the following workaround:
1

Update your global CSS file

Add the following CSS to your global CSS file (e.g., styles/globals.css):
#headlessui-portal-root {
  pointer-events: auto;
}
This will apply pointer-events: auto; to the Turnkey modal portal, allowing it to receive pointer events even when other portals are open.
2

Modify your Radix UI components

You need to prevent outside click events from closing the Radix UI components when the Turnkey modal is open.You can do this by adding the following onPointerDownOutside handler to your Radix UI components:
import { useModal } from "@turnkey/react-wallet-kit";
import * as Dialog from "@radix-ui/react-dialog";

const { modalStack } = useModal();  // Get the modal stack from Turnkey's modal system
return (
  {/* Your dialog root, trigger, overlay, etc. */}
  <Dialog.Content
    onPointerDownOutside={(e) => {
      if (modalStack.length > 0) {
        e.preventDefault();
      }
    }}
  >
    {/* Your dialog content */}
  </Dialog.Content>
)
Overall, your Radix UI dialog component (or similar) should look something like this:
import { useModal } from "@turnkey/react-wallet-kit";
import * as Dialog from "@radix-ui/react-dialog";

function RadixDialog() {
  const { modalStack } = useModal(); // Get the modal stack from Turnkey's modal system

  return (
    <Dialog.Root>
      <Dialog.Trigger>Open Dialog</Dialog.Trigger>
      <Dialog.Portal>
        <Dialog.Overlay />
        <Dialog.Content
          onPointerDownOutside={(e) => {
            if (modalStack.length > 0) {
              e.preventDefault();
            }
          }}
        >
          {/* Your dialog content */}
        </Dialog.Content>
      </Dialog.Portal>
    </Dialog.Root>
  );
}