POST /api/v2/users Returns 409 Conflict ("User already exists") Despite No Existing Record – JIT Password Reset Flow Failing

Hi Auth0 team, I’ve hit a critical blocker in my Just-In-Time (JIT) migration lab that I believe requires a backend review. I’ve included exhaustive logs and reproduction details below.**

Tenant:** dev-cnhsg0roe6qny5na
Region: US
Environment: Production-like lab setup (custom DB connection using Azure-based legacy backend APIs)
Impact: Change Password → JIT user creation blocked, halting full migration flow

Context

I’m building a Just-In-Time (JIT) migration flow for Azure AD B2C migration into Auth0.
The project has two core components:

  1. JIT Sign-In: When a user logs in, Auth0 validates against my legacy API (LocalAccountSignIn) and creates the user dynamically in Auth0.

  2. JIT Forgot Password / Change Password: When a migrated user triggers a password reset, Auth0 calls the same legacy API (LocalAccountUserExists), and if the user is not yet in Auth0, it attempts to create them using the Management API (POST /api/v2/users).

What Works

  • JIT Sign-In: Fully functional.
    -Auth0 successfully calls my legacy endpoint, validates credentials, and creates users on-the-fly.
    -Users appear correctly under the expected connection (b2c-migrated-users-v2).
    -All environment variables and secrets are correctly configured.

Example log excerpt: LOGIN SUCCESS user_id=ray.garg@zappsec.com migration_status=completed

  • The login script creates users without going through POST /api/v2/users

  • The change password script is the only place where POST /api/v2/users is called (for JIT creation during reset).

In my current design:

  • JIT Sign-In (Login script):
    Uses the legacy LocalAccountSignIn API and returns a user profile directly to Auth0. This path does not use the Management API POST /api/v2/users. It works consistently.

  • JIT Forgot Password / Change Password (Change Password script):
    Uses LocalAccountUserExists and then calls POST /api/v2/users (Management API) only when users-by-email returns empty.
    This is the path that fails with 409 The user already exists.

What Fails

Forgot Password / Change Password flow fails consistently with:

POST /api/v2/users response status=409
{
“statusCode”: 409,
“error”: “Conflict”,
“message”: “The user already exists.”,
“errorCode”: “auth0_idp_error”
}

This occurs even when:

  • /api/v2/users-by-email returns empty ([])

  • No users exist under this connection (b2c-migrated-users-v2)

  • The user does not exist in any other connection

  • I verified this using multiple advanced API searches (see below)

What I Have Already Tried

1. Fresh Connection Creation

  • Created an entirely new custom DB connection (b2c-migrated-users-v2)

  • Copied verified scripts for login, create, get user, and change password

  • Recreated all environment variables with identical key names

  • Ensured context object was enabled in all scripts
    -JIT Sign-In on b2c-migrated-users and b2c-migrated-users-v2 works reliably → confirms config + secrets + legacy APIs are correct.
    -Only the (Forgot Password) Change Password → Management API create branch fails with 409.

2. Verified Application & M2M Toggles

  • Web App toggle → Enabled for b2c-migrated-users-v2

  • M2M App toggle → Enabled for b2c-migrated-users-v2

  • On the M2M app, Management API → Authorized with following scopes:

read:users
update:users
delete:users
create:users
update:users_app_metadata
create:user_tickets
read:connections
read:logs

3. cURL Verification (Direct Management API)

Generated M2M token:

curl --request POST \
  --url https://dev-cnhsg0roe6qny5na.us.auth0.com/oauth/token \
  --header 'content-type: application/json' \
  --data '{
    "client_id": "<client id here >",
    "client_secret": "<client secret here >",
    "audience": "https://<tenant>.us.auth0.com/api/v2/",
    "grant_type": "client_credentials"
  }'

Validated no duplicate users:

# Search by email
curl --request GET \
  --url "https://dev-cnhsg0roe6qny5na.us.auth0.com/api/v2/users?q=email%3A\"rgarg2%40ucsc.edu\"&search_engine=v3" \
  --header "authorization: Bearer <access_token>"
# → []

# Search by connection prefix
curl --request GET \
  --url "https://dev-cnhsg0roe6qny5na.us.auth0.com/api/v2/users?q=user_id%3A\"auth0%7Cb2c-migrated-users*\"&search_engine=v3" \
  --header "authorization: Bearer <access_token>"
# → []

Both queries confirm there are no visible users with this email or connection prefix.

4. Confirmed Legacy API Responses

LocalAccountUserExists returns expected JSON with success=true and valid legacy attributes.
Response sample:

{
“success”: true,
“user”: {
“user_id”: “355f33ba-d08b-4170-9ca5-0f68cf43b7c8”,
“email”: “rgarg2@ucsc.edu”,
“email_verified”: true,
“name”: “Ray (UCSC JIT test) Garg”,
“app_metadata”: { “migration_status”: “completed” }
}
}

5. Full Change Password Log Trace

CHANGE-PW DEBUG: user not in Auth0 → calling LEGACY_EXIST
CHANGE-PW LEGACY EXIST status=200 body={…}
CHANGE-PW DEBUG: BRANCH=CREATE JIT localUserId=355f33ba-d08b…
CHANGE-PW DEBUG: POST /api/v2/users connection=b2c-migrated-users-v2
CHANGE-PW DEBUG: POST /users response status=409 body={“statusCode”:409,“error”:“Conflict”,“message”:“The user already exists.”,“errorCode”:“auth0_idp_error”}

Key Observation

  • /users-by-email consistently returns zero results.

  • /users creation call fails with 409 Conflict.

  • This occurs even on a brand-new connection, suggesting the duplication check may be tenant-wide or cached, possibly at the normalized_email index layer.

What I Suspect (not confirmed)

At first I suspected a stale identity index or tombstone for rishug123@yahoo.com left behind by a previously deleted user in another connection.
However, this 409 behavior now occurs for every email I test in the JIT Forgot Password flow:

  • rgarg2@ucsc.edu

  • rishug123@yahoo.com

  • ray.garg@zappsec.com

For each of these:

  • GET /api/v2/users-by-email returns []

  • Search by user_id prefix for auth0|b2c-migrated-users* returns []

That makes me wonder if there is:

  • Some tenant-wide uniqueness constraint or

  • Some soft-deleted / cached entry that is not visible via /api/v2/users but still blocks POST /api/v2/users.

Request for Engineering Assistance

Please investigate at the tenant-level identity store for any residual or orphaned entries associated with:

  • email: rgarg2@ucsc.edu or rishug123@yahoo.com or ray.garg@zappsec.com. I’m not certain this is the root cause, but given the behavior, I’d really appreciate a deeper backend check to rule this out.

  • previous connection: b2c-migrated-users

  • current connection: b2c-migrated-users-v2

If a stale entry exists in the internal store, please purge or release it so I can test creation again.

If not, I’d like confirmation of:

  1. Whether Auth0 enforces tenant-wide uniqueness on email across multiple custom DB connections. Even if it does, i have made sure that the emails im testing with dont exist in the user directory before i try the jit forgot password flow.

  2. Whether the /users endpoint may still reference cached soft-deleted entries.

  3. Any recommended remediation beyond recreating connections (which I’ve already done).

Why This Matters

This issue blocks our JIT password-reset onboarding flow, a key stage in our Auth0 adoption.
Without resolution, no migrated user can complete their reset and activation process.
The JIT login portion works flawlessly, so we know the code path and APIs are configured correctly, this is purely a user creation conflict preventing our production go-live.

Expected Behavior

If /api/v2/users-by-email returns [], POST /api/v2/users should succeed in creating a new user under the specified connection.

Request Summary

Please assist in:

  • Verifying and clearing any orphaned identity index for rgarg2@ucsc.edu/rishug123@yahoo.com/ray.garg@zappsec.com

  • Confirming whether Auth0 imposes a hidden tenant-wide uniqueness constraint between deleted records and new connection user creation

  • Providing any mitigation or workaround that avoids the duplicate user creation error that comes from testing the jit forgot password flow

Key questions for the Auth0 team

  1. Under what conditions can POST /api/v2/users return 409 The user already exists when:

    • GET /api/v2/users-by-email returns [], and

    • No users appear for the user_id prefix tied to this connection?

  2. Are there internal uniqueness constraints (e.g. normalized email + connection) or soft-deleted records that are not visible via /api/v2/users but still block creation?

  3. Is there any tenant-level cache or index that might need to be rebuilt or cleared by Auth0 engineering when many test users have been created/deleted across multiple custom DB connections?

  4. Is there any recommended alternative pattern for:

    • JIT creation during Change Password,

    • When the user is still only in the legacy system, and

    • users-by-email returns no visible Auth0 record?

Thank you in advance.
I’ve spent several days reproducing this issue methodically across multiple connections and configurations, and I’m confident it’s not a misconfiguration or script-level bug. At this point I’ve exhausted what I can see from the configuration and scripts, and I’m leaning strongly toward this being an internal uniqueness/indexing issue rather than a script-level bug.
At this point, I’m requesting a backend-level review of the tenant’s identity index and duplicate enforcement logic.

P.S If needed, I can securely share screenshots via DM or email.