calcom/cal.diy · warning · HttpError
Username or email is already taken
Error message
Username or email is already taken
What it means
Thrown by calcomSignupHandler (HttpError, HTTP 409) when validateAndGetCorrectedUsernameAndEmail reports isValid === false in the non-team-invite signup branch. HTTP 409 signals a conflict: the username or email is already owned by an existing account.
Source
Thrown at apps/web/app/api/auth/signup/handlers/calcomSignupHandler.ts:121
teamId: foundToken?.teamId ?? null,
isSignup: true,
});
if (foundToken?.teamId) {
const existingUser = await userRepository.findByEmailWithInvitedTo({email})
if (existingUser && existingUser.invitedTo !== foundToken.teamId) {
return NextResponse.json({ message: SIGNUP_ERROR_CODES.USER_ALREADY_EXISTS }, { status: 409 });
}
}
} else {
const usernameAndEmailValidation = await validateAndGetCorrectedUsernameAndEmail({
username,
email,
isSignup: true,
});
if (!usernameAndEmailValidation.isValid) {
throw new HttpError({
statusCode: 409,
message: "Username or email is already taken",
});
}
if (!usernameAndEmailValidation.username) {
throw new HttpError({
statusCode: 422,
message: "Invalid username",
});
}
username = usernameAndEmailValidation.username;
}
// Create the customer in Stripe with ad tracking metadata
const cookieStore = await cookies();
const cookiesObj = Object.fromEntries(cookieStore.getAll().map((c) => [c.name, c.value]));View on GitHub (pinned to 176037d0af)
Solutions
- Pre-check username/email availability (debounced) before submit and suggest alternatives.
- Normalize email to lowercase and trim before checking, matching the handler's userEmail.toLowerCase().
- On 409, prompt login/password-reset instead of re-registration.
- If the user was invited to a team, include the invite token so the team branch resolves ownership rather than conflicting.
Example fix
// before
await signup({ username, email });
// after
const avail = await checkUsernameEmail({ username, email });
if (!avail.isValid) {
setErrors({ username: 'taken', email: 'taken' });
return;
}
await signup({ username: avail.username ?? username, email: email.toLowerCase() }); Defensive patterns
Strategy: validation
Validate before calling
// Debounced availability check before signup
const ok = await checkAvailability({ username, email: email.toLowerCase() });
if (!ok.available) {
setErrors({ username: ok.usernameTaken ? 'Username taken' : undefined,
email: ok.emailTaken ? 'Email taken' : undefined });
return;
}
await signup({ username, email: email.toLowerCase() }); Type guard
function isAvailabilityResult(v: unknown): v is { isValid: boolean; username?: string } {
return !!v && typeof v === 'object' &&
typeof (v as any).isValid === 'boolean';
} Try / catch
try {
await signup(payload);
} catch (e) {
if (e instanceof HttpError && e.statusCode === 409) {
promptLoginOrReset(); // offer login/reset instead of re-register
return;
}
throw e;
} Prevention
- Normalize email to lower-case before both availability check and signup.
- Suggest alternative usernames when the chosen one is taken.
- If invited to a team, always include the invite token.
When it happens
Trigger: Signup POST with a username or email that already exists in the database, when no valid team-invite token is present (the token branch handles team members separately and returns a 409 JSON instead).
Common situations: User re-registering with the same email, choosing a taken username, leftover account from a failed prior signup, case/whitespace differences not normalized before the check.
Related errors
- Invalid username
- Google Meet is already connected for this team.
- Ooo entry already exists.
- Webhook with this subscriber url already exists for this eve
- Webhook with this subscriber url already exists for this oAu
AI-assisted analysis of calcom/cal.diy@176037d0af (2026-08-12).
Data as JSON: /api/errors/933c989876592938.
Report an issue: GitHub.