server - match crashed
- Dominant language
- Java
- Stars
- 2.4k
- Forks
- 940
- Avg merge
- 2d 12h
- Merged PRs (30d)
- 160
Description
Reported in match chat, right after a spectator stopped watching from lost connection, although player (tiera3) had priority on declare blockers step, could not select a blocker.
Attempted rollback did not have any visual effect.
Interesting game log message before we gave up

Starting a new client did not help obtain a playable game state.
Server logs excerpt:
```
INFO 2024-10-17 20:50:19,818 LOST CONNECTION - YamiKuriboh [Watch: 1 ] at 81.170.109.140, sessionId: 5c4o11l-53q00u-m2drqvy7-1-m2drqw5q-4 =>[Timer-0] Main$MageServerConnectionListener.handleConnectionException
WARN 2024-10-17 20:50:19,820 SESSION CALLBACK EXCEPTION - java.io.IOException: Connection is closed, userId b7841e30-d89a-4f10-893d-0c6395be5cb1, messageId: 259 =>[GAME adafb548-125f-4cba-8df2-97a233f23f05] Session.fireCallback
FATAL 2024-10-17 20:50:19,840 GameWorker system error [adafb548-125f-4cba-8df2-97a233f23f05 - Two Player Duel; T10.DB; active: xenohedron; stack: 0]: java.util.ConcurrentModificationException =>[GAME adafb548-125f-4cba-8df2-97a233f23f05] GameWorker.call
java.util.ConcurrentModificationException
at java.util.ArrayList$Itr.checkForComodification(ArrayList.java:911)
at java.util.ArrayList$Itr.remove(ArrayList.java:875)
at mage.server.User.onLostConnection(User.java:201)
at mage.server.SessionManagerImpl.lambda$disconnect$1(SessionManagerImpl.java:130)
at java.util.Optional.ifPresent(Optional.java:159)
at mage.server.SessionManagerImpl.disconnect(SessionManagerImpl.java:129)
at mage.server.Session.fireCallback(Session.java:457)
at mage.server.User.lambda$fireCallback$0(User.java:261)
at java.util.Optional.ifPresent(Optional.java:159)
at mage.server.User.fireCallback(User.java:260)
at mage.server.game.GameSessionWatcher.lambda$inform$1(GameSessionWatcher.java:61)
at java.util.Optional.ifPresent(Optional.java:159)
at mage.server.game.GameSessionWatcher.inform(GameSessionWatcher.java:61)
at mage.server.game.GameController.informOthers(GameController.java:921)
at mage.server.game.GameController.perform(GameController.java:1033)
at mage.server.game.GameController.perform(GameController.java:1012)
at mage.server.game.GameController.select(GameController.java:888)
at mage.server.game.GameController.lambda$init$3aa0d15c$2(GameController.java:197)
at mage.game.events.EventDispatcher.fireEvent(EventDispatcher.java:28)
at mage.game.events.PlayerQueryEventSource.select(PlayerQueryEventSource.java:50)
at mage.game.GameImpl.fireSelectEvent(GameImpl.java:3006)
at mage.player.human.HumanPlayer.selectBlockers(HumanPlayer.java:2077)
at mage.game.combat.Combat.selectBlockers(Combat.java:667)
at mage.game.combat.Combat.selectBlockers(Combat.java:632)
at mage.game.turn.DeclareBlockersStep.beginStep(DeclareBlockersStep.java:37)
at mage.game.turn.Phase.prePriority(Phase.java:189)
at mage.game.turn.Phase.playStep(Phase.java:203)
at mage.game.turn.Phase.play(Phase.java:91)
at mage.game.turn.Turn.play(Turn.java:137)
at mage.game.GameImpl.playTurn(GameImpl.java:1152)
at mage.game.GameImpl.play(GameImpl.java:1059)
at mage.game.GameImpl.start(GameImpl.java:1035)
at mage.server.game.GameWorker.call(GameWorker.java:35)
at mage.server.game.GameWorker.call(GameWorker.java:16)
at java.util.concurrent.FutureTask.run(FutureTask.java:266)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
at java.lang.Thread.run(Thread.java:750)
WARN 2024-10-17 20:51:24,425 FIX command was called for game adafb548-125f-4cba-8df2-97a233f23f05 by tiera3; players: tiera3 (play), xenohedron (play); !!!NOT GAME THREAD!!! Two Player Duel; T10.DB; active: xenohedron; stack: 0 =>[CALL - 1190] GameController.attemptToFixGame
```
Probably unrelated, but we had multiple misfires when trying to launch this tournament in the first place.
Contributor guide
No contributing guide indexed for this repository
Research direction
Start with mage.server.User.onLostConnection and mage.server.SessionManagerImpl.disconnect, then follow the stack trace through GameSessionWatcher and GameController during DeclareBlockersStep. Reproduce or trace the lost-spectator-connection scenario and verify that it no longer produces ConcurrentModificationException or leaves the game unplayable.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- java
- Domain
- backend, game-dev
- Issue type
- Bug
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Stale
- Clarity
- Needs clarification
- Newbie friendliness
- 35/100