{"record":{"id":"80fc861d3f69794d","repo":"Zie619/n8n-workflows","slug":"username-or-email-already-exists","errorCode":null,"errorMessage":"Username or email already exists","messagePattern":"Username or email already exists","errorType":"exception","errorClass":"ValueError","httpStatus":400,"severity":"error","filePath":"src/user_management.py","lineNumber":175,"sourceCode":"        return hashlib.sha256(password.encode()).hexdigest()\n\n    def verify_password(self, password: str, hashed: str) -> bool:\n        \"\"\"Verify password against hash.\"\"\"\n        return self.hash_password(password) == hashed\n\n    def create_user(self, user_data: UserCreate) -> User:\n        \"\"\"Create a new user.\"\"\"\n        conn = sqlite3.connect(self.db_path)\n        cursor = conn.cursor()\n\n        try:\n            # Check if username or email already exists\n            cursor.execute(\n                \"SELECT COUNT(*) FROM users WHERE username = ? OR email = ?\",\n                (user_data.username, user_data.email),\n            )\n            if cursor.fetchone()[0] > 0:\n                raise ValueError(\"Username or email already exists\")\n\n            password_hash = self.hash_password(user_data.password)\n\n            cursor.execute(\n                \"\"\"\n                INSERT INTO users (username, email, full_name, password_hash, role)\n                VALUES (?, ?, ?, ?, ?)\n            \"\"\",\n                (\n                    user_data.username,\n                    user_data.email,\n                    user_data.full_name,\n                    password_hash,\n                    user_data.role,\n                ),\n            )\n\n            user_id = cursor.lastrowid","sourceCodeStart":157,"sourceCodeEnd":193,"githubUrl":"https://github.com/Zie619/n8n-workflows/blob/94007c1445d9258a7da116646b79473e7c7c3282/src/user_management.py#L157-L193","documentation":"UserManager.create_user() raises ValueError('Username or email already exists') when its pre-check SELECT COUNT(*) on the users table finds a row with the same username OR email. SQLite has no unique constraint enforcing this, so the check is purely application-level; the FastAPI register endpoint catches the ValueError and maps it to HTTP 400 with this detail.","triggerScenarios":"POST /auth/register with a username or email that already exists in the SQLite database (including the auto-created default 'admin'/'admin@n8n-workflows.com' account). A re-run of registration after a partial failure, or two concurrent registrations racing past the COUNT check, can also produce it (the race instead surfaces as an IntegrityError/500 if a constraint existed; here the check-then-insert is not transactional against concurrent writers).","commonSituations":"Scripts that re-seed users on every startup; users re-registering with a recycled email; the default admin account blocking a second 'admin'; concurrency races since SQLite connections are opened per call with no unique index backing the check.","solutions":["Register with a different username and/or email — the check matches either column","If re-running a seed script, make it idempotent: skip or update when the user already exists","Check existence first via GET /users/{id} or an admin list before calling create","Server-side: add UNIQUE constraints on username and email in the schema and catch sqlite3.IntegrityError to remove the race"],"exampleFix":"// before\n    if cursor.fetchone()[0] > 0:\n        raise ValueError(\"Username or email already exists\")\n\n// after (schema-backed, race-free)\n    cursor.execute(\"CREATE UNIQUE INDEX IF NOT EXISTS ux_users_username ON users(username)\")\n    cursor.execute(\"CREATE UNIQUE INDEX IF NOT EXISTS ux_users_email ON users(email)\")\n    try:\n        cursor.execute(\"INSERT INTO users (...) VALUES (...)\")\n    except sqlite3.IntegrityError:\n        raise ValueError(\"Username or email already exists\")","handlingStrategy":"validation","validationCode":"def ensure_unique(user_manager, username: str, email: str) -> None:\n    # mirrors the pre-check inside create_user to fail fast with a clear message\n    existing = user_manager.get_user_by_username(username)\n    if existing is not None:\n        raise ValueError(f\"username {username!r} taken\")\n    existing = user_manager.get_user_by_email(email)\n    if existing is not None:\n        raise ValueError(f\"email {email!r} taken\")","typeGuard":null,"tryCatchPattern":"try:\n    user = user_manager.create_user(user_data)\nexcept ValueError as e:\n    if \"already exists\" in str(e):\n        user_data.username = f\"{user_data.username}_{uuid4().hex[:6]}\"\n        user = user_manager.create_user(user_data)  # or surface to the user\n    else:\n        raise","preventionTips":["Pre-check username and email uniqueness before INSERT","Make seeding scripts idempotent (upsert or skip-existing)","Back the check with UNIQUE indexes to eliminate the concurrent-registration race"],"tags":["python","sqlite","user-management","duplicate","validation"],"backgroundTag":null,"analyzedSha":"94007c1445d9258a7da116646b79473e7c7c3282","analyzedAt":"2026-08-15T04:10:37.591Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}