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
- Do not call /auth/:provider/user when already registered — use /auth/user/:actor_type or refresh the token instead
- Clear the stored JWT/token before retrying first-user creation
- Check req.auth_context.actor_id in your client flow to branch login vs signup
- 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
- Only call /auth/:provider/user on first signup
- Inspect the JWT's actor_id claim before registering a user
- Treat 'already registered' as success and switch to login flow
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
- Customer with this email already has an account
- The user is already authenticated and cannot accept an invit
- User ID not found
- User with id: ${id} was not found
- UNAUTHORIZED
AI-assisted analysis of medusajs/medusa@5e06e544a2 (2026-08-27).
Data as JSON: /api/errors/03b4c51053b4076e.
Report an issue: GitHub.