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

  1. Ensure both players have joined (AddPlayerToGame transitions to InPlay at two players) before any move.
  2. Do not move on a Finished game — start a new one.
  3. 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

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


AI-assisted analysis of dotnet/orleans@fca799fa70 (2026-08-13). Data as JSON: /api/errors/48eed9a00a3bf155. Report an issue: GitHub.