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
- Remove the Authorization header and session cookies before calling accept (use an unauthenticated client/fetch)
- Log out of the admin dashboard before opening the invite link
- 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
- Never attach default auth headers to invite-accept clients
- Log out before opening invite links
- In tests, construct a separate SDK without auth for acceptance
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
- Authentication and authorization failures — expired tokens, bad credentials, and missing scopes.
Related errors
- Invite with id: ${id} was not found
- Customer with this email already has an account
- Locale with code: ${req.params.code} was not found
- No product ids passed to remove from price list
- Price list with id: ${id} was not found
AI-assisted analysis of medusajs/medusa@5e06e544a2 (2026-08-27).
Data as JSON: /api/errors/8c9337fdeb32536c.
Report an issue: GitHub.