dotnet/orleans · error · InvalidOperationException

You have already voted in that poll!

Error message

You have already voted in that poll!

What it means

Thrown by Voting UserAgentGrain.AddVote when the user has already voted in the given poll (_votedPolls.Contains(pollId)). The user agent records each poll a user has voted in to prevent double-voting at the per-user level (in addition to whatever the PollGrain enforces).

Source

Thrown at samples/Voting/Grains/UserAgentGrain.cs:70

        var pollId = Guid.NewGuid().ToString("N")[..6];
        var pollGrain = _grainFactory.GetGrain<IPollGrain>(pollId);

        // Create the poll. We could avoid collisions here by making this return an error if a poll
        // with that id already exists.
        await pollGrain.CreatePoll(initialState);

        _myPolls.Add(pollId);
        return pollId;
    }

    public async Task<PollState> AddVote(string pollId, int optionId)
    {
        Throttle();

        // First, check to see whether we've voted already.
        if (_votedPolls.Contains(pollId))
        {
            throw new InvalidOperationException("You have already voted in that poll!");
        }

        // Vote
        var pollGrain = _grainFactory.GetGrain<IPollGrain>(pollId);
        var result = await pollGrain.AddVote(optionId);

        // Record our vote to prevent double-voting.
        _votedPolls.Add(pollId);
        return result;
    }

    private void Throttle()
    {
        // Work out how long it's been since the last call.
        var elapsedSeconds = _stopwatch.Elapsed.TotalSeconds;
        _stopwatch.Restart();

        // Calculate a new score based on a constant rate of score decay and the

View on GitHub (pinned to fca799fa70)

Solutions

  1. Do not re-vote in the same poll; the sample does not support changing a vote.
  2. If changing votes is a requirement, remove the pollId from _votedPolls (and decrement the prior option) before allowing a new vote.
  3. Catch InvalidOperationException client-side and inform the user they already voted.

Example fix

// before
await user.AddVote(pollId, optionId); // throws the second time

// after: check before voting
if (await user.HasVoted(pollId)) { ShowMessage("Already voted."); return; }
await user.AddVote(pollId, optionId);
Defensive patterns

Strategy: validation

Validate before calling

// Check the user's voted set before voting
if (await user.HasVoted(pollId)) { ShowMessage("Already voted."); return; }
await user.AddVote(pollId, optionId);

Type guard

null

Try / catch

try { await user.AddVote(pollId, optionId); }
catch (InvalidOperationException ex) when (ex.Message.Contains("already voted"))
{ /* user already voted in this poll */ }

Prevention

When it happens

Trigger: The same user calls AddVote(pollId, optionId) twice for the same pollId; the second call finds pollId already in the _votedPolls set.

Common situations: A client retrying a vote; a UI that allows clicking vote again; the user genuinely trying to change their vote (not supported by this sample).

Related errors


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