From 72e8fe8ee4cb4007950d5a6578f872cc1c08ae35 Mon Sep 17 00:00:00 2001 From: padreug Date: Tue, 11 Nov 2025 19:47:17 +0100 Subject: [PATCH] Fix UNIQUE constraint error in get_or_create_user_account MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Handles race condition where user account already exists from initial sync but without user_id set. When user configures wallet, code now: - Catches IntegrityError on UNIQUE constraint for accounts.name - Fetches existing account by name - Updates user_id if NULL or different - Returns existing account instead of failing This fixes the error that occurred when users configured their wallet after their accounts were created during the initial Beancount sync. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude --- crud.py | 53 ++++++++++++++++++++++++++++++++++++++++++++++------- 1 file changed, 46 insertions(+), 7 deletions(-) diff --git a/crud.py b/crud.py index fbb9317..caa6c06 100644 --- a/crud.py +++ b/crud.py @@ -283,14 +283,53 @@ async def get_or_create_user_account( logger.error(f"[CASTLE DB] Account still not found after sync: {account_name}") # Fallback: create directly in Castle DB if sync failed logger.info(f"[CASTLE DB] Creating account directly in Castle DB: {account_name}") - account = await create_account( - CreateAccount( - name=account_name, - account_type=account_type, - description=f"User-specific {account_type.value} account", - user_id=user_id, + try: + account = await create_account( + CreateAccount( + name=account_name, + account_type=account_type, + description=f"User-specific {account_type.value} account", + user_id=user_id, + ) ) - ) + except Exception as e: + # Handle UNIQUE constraint error - account already exists + if "UNIQUE constraint failed" in str(e) and "accounts.name" in str(e): + logger.warning(f"[CASTLE DB] Account already exists (UNIQUE constraint), fetching by name: {account_name}") + # Fetch existing account by name only (ignore user_id in query) + account = await db.fetchone( + """ + SELECT * FROM accounts + WHERE name = :name + """, + {"name": account_name}, + Account, + ) + if account: + logger.info(f"[CASTLE DB] Found existing account: {account_name} (user_id: {account.user_id})") + # Update user_id if it's NULL or different + if account.user_id != user_id: + logger.info(f"[CASTLE DB] Updating account user_id from {account.user_id} to {user_id}") + await db.execute( + """ + UPDATE accounts + SET user_id = :user_id + WHERE name = :name + """, + {"user_id": user_id, "name": account_name} + ) + # Refresh account from DB + account = await db.fetchone( + """ + SELECT * FROM accounts + WHERE name = :name + """, + {"name": account_name}, + Account, + ) + else: + # Re-raise if it's a different error + raise else: logger.info(f"[CASTLE DB] Account already exists in Castle DB: {account_name}")