You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Describe the bug
A race condition occurs when multiple users (or the same user with rapid clicks) trigger the "Start Game" action at nearly the same time. Because card dealing and the started_at timestamp update are not wrapped in a transaction — and there is no unique constraint on DealtCard — both requests pass the game.started_at == nil check and then both execute the full card-dealing loop. This results in every card from the deck being inserted twice.
Observed behavior
Normal (single click): each player receives exactly 26 unique cards (correct for a 3-player game)
Race condition triggered (two near-simultaneous "Start Game" clicks): each player receives 52 cards (the entire deck is dealt twice)
Before
2026-03-04.05-52-32.mp4
After (triggered the start game same time with mobile and laptop , mobile is not shown in the video because this is a screen recording)
2026-03-04.05-55-47.mp4
Expected behavior
Clicking "Start Game" should deal each card exactly once, mark the game as started (started_at set), and prevent any concurrent dealing process from duplicating cards.
Steps to reproduce
1. Create/join a game with >2 players
2. Ensure game is ready to start (both players present, deck loaded)
3. Have two browser tabs (or two users) click "Start Game" within ~100–300 ms of each other
4. Check the dealt cards — each player will have 52 cards instead of 26
Desktop environment
OS: Windows
Browser: Chrome
Version: 130+ (also reproducible in Edge/Firefox)
Additional context
Root cause: Repo.insert! calls in show.ex (lines ~77–84) run outside a transaction
No unique index exists on dealt_cards (card_id) or (card_id, player_id)
The started_at nil check is not atomic with the inserts
Fix suggestion: wrap both the card inserts and update_game call in Repo.transaction/1 (as previously shown)
Describe the bug
A race condition occurs when multiple users (or the same user with rapid clicks) trigger the "Start Game" action at nearly the same time. Because card dealing and the
started_attimestamp update are not wrapped in a transaction — and there is no unique constraint onDealtCard— both requests pass thegame.started_at == nilcheck and then both execute the full card-dealing loop. This results in every card from the deck being inserted twice.Observed behavior
Normal (single click): each player receives exactly 26 unique cards (correct for a 3-player game)
Race condition triggered (two near-simultaneous "Start Game" clicks): each player receives 52 cards (the entire deck is dealt twice)
Before
2026-03-04.05-52-32.mp4
After (triggered the start game same time with mobile and laptop , mobile is not shown in the video because this is a screen recording)
2026-03-04.05-55-47.mp4
Expected behavior
Clicking "Start Game" should deal each card exactly once, mark the game as started (
started_atset), and prevent any concurrent dealing process from duplicating cards.Steps to reproduce
1. Create/join a game with >2 players
2. Ensure game is ready to start (both players present, deck loaded)
3. Have two browser tabs (or two users) click "Start Game" within ~100–300 ms of each other
4. Check the dealt cards — each player will have 52 cards instead of 26
Desktop environment
OS: Windows
Browser: Chrome
Version: 130+ (also reproducible in Edge/Firefox)
Additional context
Repo.insert!calls inshow.ex(lines ~77–84) run outside a transactiondealt_cards (card_id)or(card_id, player_id)started_atnil check is not atomic with the insertsupdate_gamecall inRepo.transaction/1(as previously shown)