medusajs/medusa · error · MedusaError

The user is already authenticated and cannot accept an invit

Error message

The user is already authenticated and cannot accept an invite.

What it means

Thrown by POST /admin/invites/accept when req.auth_context.actor_id is set, meaning the request is already authenticated. Invite acceptance must happen on an anonymous session so the new user can be created from the token; a logged-in actor cannot consume it.

Source

Thrown at packages/medusa/src/api/admin/invites/accept/route.ts:17

import { acceptInviteWorkflow } from "@medusajs/core-flows"
import { HttpTypes, InviteWorkflow } from "@medusajs/framework/types"
import { MedusaError } from "@medusajs/framework/utils"
import {
  AuthenticatedMedusaRequest,
  MedusaResponse,
} from "@medusajs/framework/http"

export const POST = async (
  req: AuthenticatedMedusaRequest<
    HttpTypes.AdminAcceptInvite,
    HttpTypes.AdminGetInviteAcceptParams
  >,
  res: MedusaResponse<HttpTypes.AdminAcceptInviteResponse>
) => {
  if (req.auth_context.actor_id) {
    throw new MedusaError(
      MedusaError.Types.INVALID_DATA,
      "The user is already authenticated and cannot accept an invite."
    )
  }

  const input = {
    invite_token: req.filterableFields.token as string,
    auth_identity_id: req.auth_context.auth_identity_id,
    user: req.validatedBody,
  } as InviteWorkflow.AcceptInviteWorkflowInputDTO

  let users

  try {
    const { result } = await acceptInviteWorkflow(req.scope).run({ input })
    users = result
  } catch (e) {
    res.status(401).json({ message: "Unauthorized" })

View on GitHub (pinned to 5e06e544a2)

Solutions

  1. Remove the Authorization header and session cookies before calling accept (use an unauthenticated client/fetch)
  2. Log out of the admin dashboard before opening the invite link
  3. In tests, build a fresh SDK/fetch instance without auth for the accept call

Example fix

// before
await sdk.client.fetch("/admin/invites/accept", { method: "POST", body: { token } }) // sdk sends default auth header

// after
await fetch(`${baseUrl}/admin/invites/accept`, {
  method: "POST",
  headers: { "content-type": "application/json" },
  body: JSON.stringify({ token }),
})
Defensive patterns

Strategy: validation

Validate before calling

const headers: Record<string, string> = {}
delete headers["authorization"]
// use a bare fetch / fresh client with no token:
await fetch(`${baseUrl}/admin/invites/accept`, { method: "POST", body: JSON.stringify({ token }) })

Try / catch

try {
  await acceptInvite(token) // unauthenticated client
} catch (e: any) {
  if (e.statusCode === 400 && /already authenticated/.test(e.message)) {
    logoutThenRetry()
  } else throw e
}

Prevention

When it happens

Trigger: Calling POST /admin/invites/accept with an Authorization: Bearer <jwt> header or a valid admin session cookie attached.

Common situations: Opening an invite link while already logged into the admin in the same browser, SDK clients that set a default auth header on all requests, or tests that attach a token globally.

Understand the failure class

Related errors


AI-assisted analysis of medusajs/medusa@5e06e544a2 (2026-08-27). Data as JSON: /api/errors/8c9337fdeb32536c. Report an issue: GitHub.