medusajs/medusa · error · MedusaError

INVALID_DATA

INVALID_DATA

Error message

The user is already registered and cannot create a new account.

What it means

Thrown by POST /auth/:auth_provider/user when the JWT attached to the request already carries an actor_id, meaning the auth identity is already linked to a user. The endpoint is only for first-time user creation after registering an auth identity; subsequent logins should use the token endpoints instead. It maps to HTTP 400 (INVALID_DATA).

Source

Thrown at packages/medusa/src/api/auth/[auth_provider]/user/route.ts:25

  MedusaResponse,
} from "@medusajs/framework/http"
import {
  ContainerRegistrationKeys,
  MedusaError,
} from "@medusajs/framework/utils"

const ACTOR_TYPE = "user"

export const POST = async (
  req: AuthenticatedMedusaRequest,
  res: MedusaResponse
) => {
  const { auth_provider: authProvider } = req.params
  const query = req.scope.resolve(ContainerRegistrationKeys.QUERY)

  // If an actor is already linked to this auth identity, reject.
  if (req.auth_context.actor_id) {
    throw new MedusaError(
      MedusaError.Types.INVALID_DATA,
      "The user is already registered and cannot create a new account."
    )
  }

  if (!req.auth_context.user_metadata?.email) {
    throw new MedusaError(
      MedusaError.Types.INVALID_DATA,
      "Email is required to create a user account."
    )
  }

  // Check that the auth identity was created by the provider named in the route.
  const providerIdentities = await query
    .graph({
      entity: "auth_identity",
      fields: ["id", "provider_identities.provider"],
      filters: {

View on GitHub (pinned to 5e06e544a2)

Solutions

  1. Do not call /auth/:provider/user when already registered — use /auth/user/:actor_type or refresh the token instead
  2. Clear the stored JWT/token before retrying first-user creation
  3. Check req.auth_context.actor_id in your client flow to branch login vs signup
  4. If a new user is genuinely needed, authenticate with a different identity first

Example fix

// before
await sdk.auth.registerUser('emailpass', 'user', token) // token already has actor_id

// after
if (!token?.actor_id) {
  await sdk.auth.registerUser('emailpass', 'user', token)
} else {
  // already registered, just refresh
  await sdk.auth.refresh()
}
Defensive patterns

Strategy: validation

Validate before calling

// Decode stored JWT and check actor_id before calling register-user
function parseJwt(t) { return JSON.parse(atob(t.split('.')[1])) }
const claims = parseJwt(storedToken)
if (!claims.actor_id) {
  await fetch(`/auth/${provider}/user`, { method: 'POST', headers: { Authorization: `Bearer ${storedToken}` } })
}

Type guard

function needsUserRegistration(claims: { actor_id?: string }): boolean {
  return !claims.actor_id
}

Try / catch

catch (e) { if (e.type === 'invalid_data' && /already registered/.test(e.message)) { /* proceed to login/refresh */ } else throw e }

Prevention

When it happens

Trigger: Calling POST /auth/emailpass/user (or any provider's user route) with an Authorization: Bearer <jwt> whose auth_context already has actor_id set, i.e. after the user was already created for that identity.

Common situations: Client keeps calling the register-user endpoint on every login flow; front-end persists the JWT and re-runs signup; testing reuse of the same token after successful user creation.

Related errors


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