danny-avila/LibreChat · error · Error

User does not exist

Error message

User does not exist

What it means

Thrown only on the ADMIN OpenID path. The regular `'openid'` strategy is created with `createOpenIDCallback()` (existingUsersOnly falsy) and will auto-create unknown users; the `'openidAdmin'` strategy is created with `createOpenIDCallback(true)`, so when `findOpenIDUser` resolves no matching user, this guard throws before the create-user branch. Crucially, `'User does not exist'` is NOT in the callback's special-case list (which covers only domain/`AUTH_FAILED`/role messages), so it becomes `done(err)` — a hard Passport error that the authenticator routes to Express's error handler as a 500 rather than the friendly `auth_failed` redirect.

Source

Thrown at api/strategies/openidStrategy.js:683

      const rolesList =
        requiredRoles.length === 1
          ? `"${requiredRoles[0]}"`
          : `one of: ${requiredRoles.map((r) => `"${r}"`).join(', ')}`;
      throw new Error(`You must have ${rolesList} role to log in.`);
    }
  }

  let username = '';
  if (process.env.OPENID_USERNAME_CLAIM) {
    username = userinfo[process.env.OPENID_USERNAME_CLAIM];
  } else {
    username = convertToUsername(
      userinfo.preferred_username || userinfo.username || userinfo.email,
    );
  }

  if (existingUsersOnly && !user) {
    throw new Error('User does not exist');
  }

  if (!user) {
    user = {
      provider: 'openid',
      openidId: userinfo.sub,
      username,
      email: email || '',
      emailVerified: userinfo.email_verified || false,
      name: fullName,
      idOnTheSource: userinfo.oid,
      openidIssuer,
    };

    const balanceConfig = getBalanceConfig(appConfig);
    user = await createUser(user, balanceConfig, true, true);
  } else {
    user.provider = 'openid';

View on GitHub (pinned to 5ff282f900)

Solutions

  1. Pre-create the admin user document in the database with the correct `openidId` (token `sub`), `openidIssuer`, and `email` before they attempt admin SSO.
  2. Confirm the user is hitting the regular user callback (`${APPLE_CALLBACK_URL}`-style `/api/auth/openid/callback`) for normal login, not the admin callback.
  3. If this surfaces as a 500 and you want a cleaner UX, add `'User does not exist'` to the special-case list in `createOpenIDCallback` so it becomes a `done(null, false, { message })` redirect.
  4. Verify the user's stored `openidId`/`openidIssuer` still match the current IdP issuer and subject after any IdP migration.

Example fix

// before — admin-only guard throws a message that becomes a 500
if (existingUsersOnly && !user) {
  throw new Error('User does not exist');
}
// after — surface as a clean auth failure so the admin sees the login screen, not a 500
if (existingUsersOnly && !user) {
  return done(null, false, { message: 'User does not exist' });
}
Defensive patterns

Strategy: validation

Validate before calling

// For the admin path, pre-check that a matching user exists before surfacing SSO
async function adminUserExists(findUser, openidId, email) {
  return Boolean(await findUser({ $or: [{ openidId }, { email: email?.trim() }] }));
}

Type guard

function isAdminCallback(url: string): boolean {
  return url.includes('/api/admin/oauth/');
}

Try / catch

// Map 'User does not exist' to a clean auth failure instead of a 500
try {
  const user = await processOpenIDAuth(tokenset, true);
  done(null, user);
} catch (err) {
  if (err.message === 'User does not exist') return done(null, false, { message: 'Admin user not provisioned' });
  done(err);
}

Prevention

When it happens

Trigger: An administrator navigates to the admin SSO entry point (`/api/admin/oauth/openid/callback`) and authenticates against the IdP, but no user document with a matching `openidId`, `email`, or `openidIssuer` exists in the database yet. This is the intended bootstrap protection: admins must be pre-provisioned.

Common situations: First-time admin SSO setup before any admin user exists in the DB; the admin's IdP subject/email changed so the prior record no longer matches; a non-admin user accidentally using the admin callback URL; test/staging DB reset that wiped user records.

Related errors


AI-assisted analysis of danny-avila/LibreChat@5ff282f900 (2026-08-12). Data as JSON: /api/errors/664324715eb4a693. Report an issue: GitHub.