dotnet/orleans · error · ArgumentException
Bad co-ordinates for a move
Error message
Bad co-ordinates for a move
What it means
Thrown by TicTacToe GameGrain.MakeMove when move.X or move.Y is outside the 0..2 range (the board is a 3x3 grid). It guards against index-out-of-range access into the _board array before the move is recorded.
Source
Thrown at samples/TicTacToe/Grains/GameGrain.cs:77
// 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]);
}
if (!win)
{
for (var i = 0; i < 3 && !win; i++)
{
win = IsWinningLine(_board[0, i], _board[1, i], _board[2, i]);View on GitHub (pinned to fca799fa70)
Solutions
- Clamp/validate coordinates client-side to 0,1,2 before calling MakeMove.
- If your UI is one-indexed, subtract one before constructing GameMove.
- Catch ArgumentException at the call site and surface a user-facing message.
Example fix
// before await game.MakeMove(new GameMove(playerId, x, y)); // throws if x or y is 3 // after: validate on the client if (x is < 0 or > 2 || y is < 0 or > 2) return; await game.MakeMove(new GameMove(playerId, x, y));
Defensive patterns
Strategy: validation
Validate before calling
// Clamp coordinates to the 3x3 board if (move.X is < 0 or > 2 || move.Y is < 0 or > 2) return; await game.MakeMove(move);
Type guard
static bool IsValidMove(GameMove move)
=> move.X is >= 0 and <= 2 && move.Y is >= 0 and <= 2; Try / catch
null
Prevention
- Constrain the client UI so only valid cells can be selected.
- If your UI is one-indexed, subtract one before constructing GameMove.
- Validate bounds on the client before the round trip.
When it happens
Trigger: A client submits a GameMove with X or Y less than 0 or greater than 2. The bounds check `move.X < 0 || move.X > 2 || move.Y < 0 || move.Y > 2` fires.
Common situations: A client UI letting the user click outside the 3x3 grid; off-by-one or one-indexed coordinates from the client; deserializing a malformed move.
Related errors
- Can't join game once its over
- This game is not in play
- No such playerid for this game
- Missing value for {name}.
- Invalid option {optionId}
AI-assisted analysis of dotnet/orleans@fca799fa70 (2026-08-13).
Data as JSON: /api/errors/1999effa0d85ec7d.
Report an issue: GitHub.