Skip to content

Bug: handle_event("next_round") always executes unconditional DB fetch and broadcast — intermediate returns are dead code #2632

Description

@immortal71

Describe the bug

In player_live/show.ex, handle_event("next_round", ...) contains two early {:noreply, ...} returns inside the if round_open? branches. Because these are not the last expression in the function, Elixir discards them. The function always falls through to the unconditional Game.find + Endpoint.broadcast at the end.

Affected file

copi.owasp.org/lib/copi_web/live/player_live/show.ex

Code snippet

def handle_event("next_round", _, socket) do
  game = socket.assigns.game

  if round_open?(game) do
    if Copi.Cornucopia.Game.can_continue_round?(game) do
      Copi.Cornucopia.update_game(game, %{round_open: false})
      Process.send_after(self(), :proceed_to_next_round, 100)
      {:noreply, assign(socket, :game, game)}  # ← ignored; not the last expression
    else
      {:noreply, socket}                        # ← ignored; not the last expression
    end
  else
    Copi.Cornucopia.update_game(game, %{rounds_played: game.rounds_played + 1, round_open: true})
    ...
  end

  # These always execute, regardless of which branch was taken above
  {:ok, updated_game} = Game.find(game.id)
  CopiWeb.Endpoint.broadcast(topic(updated_game.id), "game:updated", updated_game)
  {:noreply, assign(socket, :game, updated_game)}
end

Impact

  • When the round can't close yet (round_open? && !can_continue?), the handler is supposed to be a no-op, but it still executes a Game.find DB query and broadcasts a game:updated PubSub message to all connected players — causing unnecessary load and spurious UI reloads.
  • The intended early returns are dead code and will never be the actual function return value.

Expected behavior

When no state change occurs (round is open and cannot yet continue), the handler should return {:noreply, socket} immediately with no DB query and no broadcast.

Proposed fix

Restructure the handler so each branch is a complete, independent case/cond arm that returns its own {:noreply, ...} including the appropriate fetch and broadcast only when a state change actually occurred.

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't workingcopi.owasp.orgelixirPull requests that update elixir codehelp wantedExtra attention is needed

    Type

    No type

    Fields

    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions