dotnet/orleans · error · ApplicationException
This game is not in play
Error message
This game is not in play
What it means
Thrown by TicTacToe GameGrain.MakeMove when _gameState is not GameState.InPlay — moves are only legal during active play. This is the primary state-machine guard on the move path; it precedes the player/co-ordinate validation checks.
Source
Thrown at samples/TicTacToe/Grains/GameGrain.cs:72
_playerIds.Add(player);
// check if the game is ready to play
if (_gameState is GameState.AwaitingPlayers && _playerIds.Count is 2)
{
// a new game is starting
_gameState = GameState.InPlay;
_indexNextPlayerToMove = Random.Shared.Next(0, 1); // random as to who has the first move
}
// let user know if game is ready or not
return Task.FromResult(_gameState);
}
// make a move during the game
public async Task<GameState> MakeMove(GameMove move)
{
// check if its a legal move to make
if (_gameState is not GameState.InPlay) throw new ApplicationException("This game is not in play");
if (_playerIds.IndexOf(move.PlayerId) < 0) throw new ArgumentException("No such playerid for this game", "move");
if (move.PlayerId != _playerIds[_indexNextPlayerToMove]) throw new ArgumentException("The wrong player tried to make a move", "move");
if (move.X < 0 || move.X > 2 || move.Y < 0 || move.Y > 2) throw new ArgumentException("Bad co-ordinates for a move", "move");
if (_board[move.X, move.Y] != -1) throw new ArgumentException("That square is not empty", "move");
// record move
_moves.Add(move);
_board[move.X, move.Y] = _indexNextPlayerToMove;
// check for a winning move
var win = false;
for (var i = 0; i < 3 && !win; i++)
{
win = IsWinningLine(_board[i, 0], _board[i, 1], _board[i, 2]);
}
View on GitHub (pinned to fca799fa70)
Solutions
- Ensure both players have joined (AddPlayerToGame transitions to InPlay at two players) before any move.
- Do not move on a Finished game — start a new one.
- Have the client track GameState and only call MakeMove when InPlay.
Example fix
// before await game.MakeMove(move); // throws if not InPlay // after: guard on the client using the returned game state if (await game.GetState() != GameState.InPlay) return; await game.MakeMove(move);
Defensive patterns
Strategy: validation
Validate before calling
// Only move while the game is in play if (await game.GetState() != GameState.InPlay) return; await game.MakeMove(move);
Type guard
null
Try / catch
try { await game.MakeMove(move); }
catch (ApplicationException ex) when (ex.Message.Contains("not in play"))
{ /* refresh state, wait for second player */ } Prevention
- Ensure both players have joined (transition to InPlay) before moving.
- Never move on a Finished game.
- Drive the client off the returned GameState rather than assumptions.
When it happens
Trigger: A client calls MakeMove(move) while the game is AwaitingPlayers (fewer than two players) or Finished. The check `if (_gameState is not GameState.InPlay)` fires before any board validation.
Common situations: Submitting a move before both players have joined; moving on a game that already has a winner; a race where the second player has not yet triggered the AwaitingPlayers->InPlay transition.
Related errors
- Can't join game once its over
- No such playerid for this game
- Bad co-ordinates for a move
- Missing value for {name}.
- Invalid option {optionId}
AI-assisted analysis of dotnet/orleans@fca799fa70 (2026-08-13).
Data as JSON: /api/errors/48eed9a00a3bf155.
Report an issue: GitHub.