{"record":{"id":"d79c4e2426e87a91","repo":"langfuse/langfuse","slug":"error-d79c4e","errorCode":null,"errorMessage":"{}","messagePattern":"\\{\\}","errorType":"http","errorClass":null,"httpStatus":422,"severity":"warning","filePath":"web/src/pages/api/auth/signup-verify.ts","lineNumber":54,"sourceCode":"  }\n\n  const parsed = signupVerifySchema.safeParse(req.body);\n  if (!parsed.success) {\n    res\n      .status(422)\n      .json({ message: parsed.error.issues[0]?.message ?? \"Invalid input\" });\n    return;\n  }\n\n  const { email, name } = parsed.data;\n  const normalizedEmail = email.toLowerCase();\n\n  // Run eligibility checks (signup disabled, SSO enforcement, etc.)\n  const eligibilityError = await validateSignupEligibility({\n    email: normalizedEmail,\n  });\n  if (eligibilityError) {\n    res.status(422).json({ message: eligibilityError });\n    return;\n  }\n\n  // Check if user already exists\n  const existingUser = await prisma.user.findUnique({\n    where: { email: normalizedEmail },\n  });\n\n  if (existingUser) {\n    if (existingUser.password !== null) {\n      // User already has a password — they completed signup before\n      res.status(422).json({\n        message: \"User with email already exists. Please sign in.\",\n      });\n      return;\n    }\n    // Passwordless user exists (abandoned previous attempt) — allow re-sending OTP\n    res.status(200).json({ status: \"ok\" });","sourceCodeStart":36,"sourceCodeEnd":72,"githubUrl":"https://github.com/langfuse/langfuse/blob/59d92c7cf365150d10b753b5a0d1708902a2ed60/web/src/pages/api/auth/signup-verify.ts#L36-L72","documentation":"validateSignupEligibility returned a non-empty string, so the endpoint rejects the signup with 422. The empty '{}' message means the serialized error payload was empty — the eligibility failure reason itself was logged under a different key. Eligibility covers signup being disabled, SSO enforcement, allowlists, etc.","triggerScenarios":"POST /api/auth/signup-verify with an email that is required to use SSO (AUTH_FORCE_SESSION or org SSO enforcement), or when signup is disabled via env (e.g. AUTH_DISABLE_SIGNUP), or the email fails an allow/deny list.","commonSituations":"Self-hosted instances with AUTH_DISABLE_SIGNUP=true; enterprise orgs enforcing SSO where email-password signup is blocked; NEXT_PUBLIC_SIGN_UP_DISABLED features.","solutions":["Check the returned message body (eligibilityError string) for the real reason — '{}' suggests logging/serialization mismatch","Verify signup-related env vars: AUTH_DISABLE_SIGNUP, SSO enforcement flags","If the email belongs to an SSO-enforced org, complete signup via the SSO flow instead of email OTP"],"exampleFix":null,"handlingStrategy":"validation","validationCode":"const res = await fetch('/api/auth/signup-verify', {...});\nif (res.status === 422) {\n  const { message } = await res.json();\n  if (/sso/i.test(message)) redirect('/auth/signin/sso');\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Surface the eligibility error message to the user verbatim — it explains SSO/disable reasons","Detect SSO-enforced emails and route to the SSO sign-in flow before attempting signup","Self-hosters: document AUTH_DISABLE_SIGNUP so users know signup is intentionally closed"],"tags":["signup","sso","eligibility","authorization"],"backgroundTag":"signup-disabled-or-sso-enforced","analyzedSha":"59d92c7cf365150d10b753b5a0d1708902a2ed60","analyzedAt":"2026-08-27T22:22:00.402Z","schemaVersion":2},"datasetVersion":"2026-08-28T00:17:15.603Z"}