{"record":{"id":"a96160e013e67de2","repo":"dotnet/orleans","slug":"no-such-playerid-for-this-game","errorCode":null,"errorMessage":"No such playerid for this game","messagePattern":"No such playerid for this game","errorType":"exception","errorClass":"ArgumentException","httpStatus":null,"severity":"error","filePath":"samples/TicTacToe/Grains/GameGrain.cs","lineNumber":74,"sourceCode":"        // check if the game is ready to play\n        if (_gameState is GameState.AwaitingPlayers && _playerIds.Count is 2)\n        {\n            // 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        {","sourceCodeStart":56,"sourceCodeEnd":92,"githubUrl":"https://github.com/dotnet/orleans/blob/fca799fa70ecb6ad975224271703ca43221f58de/samples/TicTacToe/Grains/GameGrain.cs#L56-L92","documentation":"Thrown by TicTacToe GameGrain.MakeMove when move.PlayerId is not found in _playerIds (IndexOf returns < 0). It validates that the move came from a player actually seated at this game. The second argument \"move\" is the legacy string-based paramName form.","triggerScenarios":"A client passes a GameMove whose PlayerId does not match either of the two Guids added via AddPlayerToGame. IndexOf(playerId) on _playerIds is negative.","commonSituations":"Generating a new player Guid per call instead of reusing the one from AddPlayerToGame; cross-talking to the wrong game grain; a client bug that sends another user's id.","solutions":["Use the same player Guid returned/used during AddPlayerToGame for every subsequent MakeMove.","Confirm the GameMove.PlayerId is one of the two registered players before submitting.","If you need to identify the caller, pass the player id consistently from the client."],"exampleFix":"// before\nawait game.MakeMove(new GameMove(Guid.NewGuid(), x, y)); // new id each call -> throws\n\n// after: reuse the registered player id\nawait game.MakeMove(new GameMove(myPlayerId, x, y));","handlingStrategy":"validation","validationCode":"// Reuse the registered player id for every move\nawait game.MakeMove(new GameMove(myPlayerId, x, y));","typeGuard":"// Ensure the move references a known player\nstatic bool IsValidPlayer(GameMove move, IReadOnlyList<Guid> players)\n    => players.Contains(move.PlayerId);","tryCatchPattern":"null","preventionTips":["Use the same player Guid from AddPlayerToGame for all moves.","Do not generate a new player id per call.","Validate the caller's player id on the client before submitting."],"tags":["game","validation","player-id","sample"],"backgroundTag":null,"analyzedSha":"fca799fa70ecb6ad975224271703ca43221f58de","analyzedAt":"2026-08-13T19:55:57.938Z","schemaVersion":2},"datasetVersion":"2026-08-14T00:17:13.853Z"}