getredash/redash · error
Email already taken.
Error message
Email already taken.
What it means
Raised by UserListResource.post in redash/handlers/users.py when models.db.session.commit() raises an IntegrityError whose message contains 'email' — the org+email unique constraint was violated, so a user with that email already exists in the organization.
Source
Thrown at redash/handlers/users.py:152
if "@" not in req["email"]:
abort(400, message="Bad email address.")
require_allowed_email(req["email"])
user = models.User(
org=self.current_org,
name=req["name"],
email=req["email"],
is_invitation_pending=True,
group_ids=[self.current_org.default_group.id],
)
try:
models.db.session.add(user)
models.db.session.commit()
except IntegrityError as e:
if "email" in str(e):
abort(400, message="Email already taken.")
abort(500)
self.record_event({"action": "create", "object_id": user.id, "object_type": "user"})
should_send_invitation = "no_invite" not in request.args
return invite_user(self.current_org, self.current_user, user, send_email=should_send_invitation)
class UserInviteResource(BaseResource):
@require_admin
def post(self, user_id):
user = models.User.get_by_id_and_org(user_id, self.current_org)
return invite_user(self.current_org, self.current_user, user)
class UserResetPasswordResource(BaseResource):
@require_admin
def post(self, user_id):View on GitHub (pinned to ca79fe988d)
Solutions
- Check for an existing user first (GET /api/users?email=...) and reuse it instead of re-inviting.
- Make invite scripts idempotent: on this 400, look up and return the existing user.
- De-duplicate your invitation list before submitting.
Example fix
# before
client.post('/api/users', json={'name': 'X', 'email': email})
# after
existing = client.get('/api/users', params={'email': email})['results']
if not existing:
client.post('/api/users', json={'name': 'X', 'email': email}) Defensive patterns
Strategy: validation
Validate before calling
existing = client.get('/api/users', params={'email': email})['results']
if existing:
return existing[0] Try / catch
try:
client.post('/api/users', json=payload)
except HTTPError as e:
if e.response.status_code == 400 and 'already taken' in e.response.text:
return get_user_by_email(email)
raise Prevention
- Make invite scripts idempotent by checking email existence first.
- De-duplicate invitation lists before submission.
When it happens
Trigger: POST /api/users inviting an email that is already registered in the same org (active or previously invited).
Common situations: Re-running invite scripts that are not idempotent; inviting someone who already signed up via SSO; retrying after a timeout duplicates the invite.
Related errors
- Bad email address.
- Not found
- Must provide current password to update password.
- Incorrect current password.
- Must be admin to change groups membership.
AI-assisted analysis of getredash/redash@ca79fe988d (2026-08-28).
Data as JSON: /api/errors/f8309d9a2b12f3f3.
Report an issue: GitHub.