{"record":{"id":"1999effa0d85ec7d","repo":"dotnet/orleans","slug":"bad-co-ordinates-for-a-move","errorCode":null,"errorMessage":"Bad co-ordinates for a move","messagePattern":"Bad co-ordinates for a move","errorType":"exception","errorClass":"ArgumentException","httpStatus":null,"severity":"error","filePath":"samples/TicTacToe/Grains/GameGrain.cs","lineNumber":77,"sourceCode":"            // a new game is starting\n            _gameState = GameState.InPlay;\n            _indexNextPlayerToMove = Random.Shared.Next(0, 1);  // random as to who has the first move\n        }\n\n        // let user know if game is ready or not\n        return Task.FromResult(_gameState);\n    }\n\n    // make a move during the game\n    public async Task<GameState> MakeMove(GameMove move)\n    {\n        // check if its a legal move to make\n        if (_gameState is not GameState.InPlay) throw new ApplicationException(\"This game is not in play\");\n\n        if (_playerIds.IndexOf(move.PlayerId) < 0) throw new ArgumentException(\"No such playerid for this game\", \"move\");\n        if (move.PlayerId != _playerIds[_indexNextPlayerToMove]) throw new ArgumentException(\"The wrong player tried to make a move\", \"move\");\n\n        if (move.X < 0 || move.X > 2 || move.Y < 0 || move.Y > 2) throw new ArgumentException(\"Bad co-ordinates for a move\", \"move\");\n        if (_board[move.X, move.Y] != -1) throw new ArgumentException(\"That square is not empty\", \"move\");\n\n        // record move\n        _moves.Add(move);\n        _board[move.X, move.Y] = _indexNextPlayerToMove;\n\n        // check for a winning move\n        var win = false;\n        for (var i = 0; i < 3 && !win; i++)\n        {\n            win = IsWinningLine(_board[i, 0], _board[i, 1], _board[i, 2]);\n        }\n\n        if (!win)\n        {\n            for (var i = 0; i < 3 && !win; i++)\n            {\n                win = IsWinningLine(_board[0, i], _board[1, i], _board[2, i]);","sourceCodeStart":59,"sourceCodeEnd":95,"githubUrl":"https://github.com/dotnet/orleans/blob/fca799fa70ecb6ad975224271703ca43221f58de/samples/TicTacToe/Grains/GameGrain.cs#L59-L95","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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."],"exampleFix":"// before\nawait game.MakeMove(new GameMove(playerId, x, y)); // throws if x or y is 3\n\n// after: validate on the client\nif (x is < 0 or > 2 || y is < 0 or > 2) return;\nawait game.MakeMove(new GameMove(playerId, x, y));","handlingStrategy":"validation","validationCode":"// Clamp coordinates to the 3x3 board\nif (move.X is < 0 or > 2 || move.Y is < 0 or > 2) return;\nawait game.MakeMove(move);","typeGuard":"static bool IsValidMove(GameMove move)\n    => move.X is >= 0 and <= 2 && move.Y is >= 0 and <= 2;","tryCatchPattern":"null","preventionTips":["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."],"tags":["game","validation","coordinates","bounds","sample"],"backgroundTag":null,"analyzedSha":"fca799fa70ecb6ad975224271703ca43221f58de","analyzedAt":"2026-08-13T19:55:57.938Z","schemaVersion":2},"datasetVersion":"2026-08-14T00:17:13.853Z"}