Unauthenticated admin: SessionNotFoundError

I’m currently building a Shopify Remix app and running into an issue with an unauthenticated route (triggered from a Checkout UI Extension).

I’m using authenticate.public.checkout(request) successfully, but when I try to create the unauthenticated admin context using the resulting sessionToken.dest, I get the following error:

SessionNotFoundError: Could not find a session for shop example.myshopify.com when creating unauthenticated admin context
    at Object.admin (file:///app/node_modules/@shopify/src/server/unauthenticated/admin/factory.ts:21:13)
    at action$7 (file:///app/build/server/index.js?t=1756400681282.2126:108:21)
    at Object.callRouteAction (/app/node_modules/@remix-run/server-runtime/dist/data.js:36:16)
    at /app/node_modules/@remix-run/router/router.ts:4934:19
    at callLoaderOrAction (/app/node_modules/@remix-run/router/router.ts:4998:16)
    at async Promise.all (index 0)
    at defaultDataStrategy (/app/node_modules/@remix-run/router/router.ts:4807:17)
    at callDataStrategyImpl (/app/node_modules/@remix-run/router/router.ts:4870:17)
    at callDataStrategy (/app/node_modules/@remix-run/router/router.ts:4027:19)
    at submit (/app/node_modules/@remix-run/router/router.ts:3790:21)

Here’s a simplified version of my code:

export const action = async ({ request }) => {
  const { sessionToken, cors } = await authenticate.public.checkout(request);
  const { admin } = await unauthenticated.admin(sessionToken.dest); // ⛔️ throws error

  // ... omitted mutation for clarity

  return cors(json({ success: true }));
};
  • The unauthenticated.admin(…) method expects a shop domain as a string (e.g. example.myshopify.com) — but is there a way to pass a session directly instead?

  • In my case, sessionToken.dest is a string, and it contains the shop domain (example.myshopify.com) — so it seems correct. Still, the session is not found.

That error happens because unauthenticated.admin(...) doesn’t actually look up an existing session. Instead, it expects either:

  • A shop domain string (e.g. "``example.myshopify.com``") that it can use to bootstrap the client, and an API access token (from your app’s configuration).

  • Or, in some cases, a session object from authenticate.admin(...) (but that’s not available in checkout/public contexts).

In your example:

const { sessionToken, cors } = await authenticate.public.checkout(request);

// sessionToken.dest does give you "example.myshopify.com"
const { admin } = await unauthenticated.admin(sessionToken.dest);

What’s missing here is that unauthenticated.admin(shop) doesn’t pull from your session token — it pulls from your app’s config (client ID + secret / admin API token).

Fix: Pass in the shop domain string directly, but make sure you’ve configured your app with an Admin API access token (from your app’s setup in Partners). For example:

import { unauthenticated } from "@shopify/shopify-api";

export const action = async ({ request }) => {
  const { sessionToken, cors } = await authenticate.public.checkout(request);

  // Pass the shop domain (string)
  const { admin } = await unauthenticated.admin(sessionToken.dest);

  // Now you can run admin queries/mutations
  const response = await admin.graphql(
    `#graphql
      {
        shop {
          name
        }
      }
    `
  );

  return cors(json({ success: true, shop: await response.json() }));
};

Extra tip:

  • If you only need storefront/checkout context, stick to authenticate.public.checkout it’s lighter weight.

  • Use unauthenticated.admin(shop) only if you absolutely need Admin API calls from inside an extension.

  • If you get stuck, check that your app has the right Admin API scopes enabled in shopify.app.toml.

So to answer your direct question:
You can’t pass a session object into unauthenticated.admin. It strictly takes the shop domain string, and uses your app’s config to spin up an admin client.

If you ever need help in doing this you can reach me at: matjames694-at-gmail-com

for anyone having this error. It may be the case in which your app was not authenticated in the store. It will easily happens in shopify app dev if you do not access any admin endpoint from your App portal before accessing this endpoint.

accessing from your browser https://your-ngrok-or-dev-host-proxy.trycloudflare.com/auth?shop=bobshop.myshopify.com and then insert your store would solve. Accessing any app admin endpoint will also authenticate

No, you can’t pass a session directly, and unauthenticated.admin(shop) will only work if your app already has a stored offline admin session for that shop.

authenticate.public.checkout() gives you a checkout JWT, not an app session. Even though sessionToken.dest contains the shop domain, there is no session in your app’s session storage, so unauthenticated.admin() fails with SessionNotFoundError.

To fix this, the app must be installed and have completed OAuth at least once (creating an offline session), or you must move the Admin API call to an authenticated route.