{"record":{"id":"f8309d9a2b12f3f3","repo":"getredash/redash","slug":"email-already-taken","errorCode":null,"errorMessage":"Email already taken.","messagePattern":"Email already taken\\.","errorType":"http","errorClass":null,"httpStatus":400,"severity":"error","filePath":"redash/handlers/users.py","lineNumber":152,"sourceCode":"\n        if \"@\" not in req[\"email\"]:\n            abort(400, message=\"Bad email address.\")\n        require_allowed_email(req[\"email\"])\n\n        user = models.User(\n            org=self.current_org,\n            name=req[\"name\"],\n            email=req[\"email\"],\n            is_invitation_pending=True,\n            group_ids=[self.current_org.default_group.id],\n        )\n\n        try:\n            models.db.session.add(user)\n            models.db.session.commit()\n        except IntegrityError as e:\n            if \"email\" in str(e):\n                abort(400, message=\"Email already taken.\")\n            abort(500)\n\n        self.record_event({\"action\": \"create\", \"object_id\": user.id, \"object_type\": \"user\"})\n\n        should_send_invitation = \"no_invite\" not in request.args\n        return invite_user(self.current_org, self.current_user, user, send_email=should_send_invitation)\n\n\nclass UserInviteResource(BaseResource):\n    @require_admin\n    def post(self, user_id):\n        user = models.User.get_by_id_and_org(user_id, self.current_org)\n        return invite_user(self.current_org, self.current_user, user)\n\n\nclass UserResetPasswordResource(BaseResource):\n    @require_admin\n    def post(self, user_id):","sourceCodeStart":134,"sourceCodeEnd":170,"githubUrl":"https://github.com/getredash/redash/blob/ca79fe988d81cdac9675b412f3dfcab107bc1fbc/redash/handlers/users.py#L134-L170","documentation":"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.","triggerScenarios":"POST /api/users inviting an email that is already registered in the same org (active or previously invited).","commonSituations":"Re-running invite scripts that are not idempotent; inviting someone who already signed up via SSO; retrying after a timeout duplicates the invite.","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."],"exampleFix":"# before\nclient.post('/api/users', json={'name': 'X', 'email': email})\n\n# after\nexisting = client.get('/api/users', params={'email': email})['results']\nif not existing:\n    client.post('/api/users', json={'name': 'X', 'email': email})","handlingStrategy":"validation","validationCode":"existing = client.get('/api/users', params={'email': email})['results']\nif existing:\n    return existing[0]","typeGuard":null,"tryCatchPattern":"try:\n    client.post('/api/users', json=payload)\nexcept HTTPError as e:\n    if e.response.status_code == 400 and 'already taken' in e.response.text:\n        return get_user_by_email(email)\n    raise","preventionTips":["Make invite scripts idempotent by checking email existence first.","De-duplicate invitation lists before submission."],"tags":["redash","users","duplicate","email","conflict"],"backgroundTag":"duplicate-unique-constraint","analyzedSha":"ca79fe988d81cdac9675b412f3dfcab107bc1fbc","analyzedAt":"2026-08-28T18:32:34.637Z","schemaVersion":2},"datasetVersion":"2026-08-28T21:17:43.275Z"}