{"record":{"id":"664324715eb4a693","repo":"danny-avila/LibreChat","slug":"user-does-not-exist","errorCode":null,"errorMessage":"User does not exist","messagePattern":"User does not exist","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"api/strategies/openidStrategy.js","lineNumber":683,"sourceCode":"      const rolesList =\n        requiredRoles.length === 1\n          ? `\"${requiredRoles[0]}\"`\n          : `one of: ${requiredRoles.map((r) => `\"${r}\"`).join(', ')}`;\n      throw new Error(`You must have ${rolesList} role to log in.`);\n    }\n  }\n\n  let username = '';\n  if (process.env.OPENID_USERNAME_CLAIM) {\n    username = userinfo[process.env.OPENID_USERNAME_CLAIM];\n  } else {\n    username = convertToUsername(\n      userinfo.preferred_username || userinfo.username || userinfo.email,\n    );\n  }\n\n  if (existingUsersOnly && !user) {\n    throw new Error('User does not exist');\n  }\n\n  if (!user) {\n    user = {\n      provider: 'openid',\n      openidId: userinfo.sub,\n      username,\n      email: email || '',\n      emailVerified: userinfo.email_verified || false,\n      name: fullName,\n      idOnTheSource: userinfo.oid,\n      openidIssuer,\n    };\n\n    const balanceConfig = getBalanceConfig(appConfig);\n    user = await createUser(user, balanceConfig, true, true);\n  } else {\n    user.provider = 'openid';","sourceCodeStart":665,"sourceCodeEnd":701,"githubUrl":"https://github.com/danny-avila/LibreChat/blob/5ff282f9006c436e561de1afd39a481bea1ef0d8/api/strategies/openidStrategy.js#L665-L701","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","solutions":["Pre-create the admin user document in the database with the correct `openidId` (token `sub`), `openidIssuer`, and `email` before they attempt admin SSO.","Confirm the user is hitting the regular user callback (`${APPLE_CALLBACK_URL}`-style `/api/auth/openid/callback`) for normal login, not the admin callback.","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.","Verify the user's stored `openidId`/`openidIssuer` still match the current IdP issuer and subject after any IdP migration."],"exampleFix":"// before — admin-only guard throws a message that becomes a 500\nif (existingUsersOnly && !user) {\n  throw new Error('User does not exist');\n}\n// after — surface as a clean auth failure so the admin sees the login screen, not a 500\nif (existingUsersOnly && !user) {\n  return done(null, false, { message: 'User does not exist' });\n}","handlingStrategy":"validation","validationCode":"// For the admin path, pre-check that a matching user exists before surfacing SSO\nasync function adminUserExists(findUser, openidId, email) {\n  return Boolean(await findUser({ $or: [{ openidId }, { email: email?.trim() }] }));\n}","typeGuard":"function isAdminCallback(url: string): boolean {\n  return url.includes('/api/admin/oauth/');\n}","tryCatchPattern":"// Map 'User does not exist' to a clean auth failure instead of a 500\ntry {\n  const user = await processOpenIDAuth(tokenset, true);\n  done(null, user);\n} catch (err) {\n  if (err.message === 'User does not exist') return done(null, false, { message: 'Admin user not provisioned' });\n  done(err);\n}","preventionTips":["Pre-provision admin user documents with the correct openidId/openidIssuer/email before enabling admin SSO.","Keep the admin callback URL distinct from the user callback and document that only pre-provisioned admins may use it.","Consider adding 'User does not exist' to the callback's special-case list so it produces a redirect rather than a 500."],"tags":["authentication","openid","admin","user-provisioning","bootstrap"],"backgroundTag":null,"analyzedSha":"5ff282f9006c436e561de1afd39a481bea1ef0d8","analyzedAt":"2026-08-12T21:38:08.145Z","schemaVersion":2},"datasetVersion":"2026-08-12T23:17:12.415Z"}