Dialyzer error - the pattern can never match the type

I’m getting the following error:

________________________________________________________________________________
lib/teiserver_web/live/account/profile/overview.ex:315:pattern_match
The pattern can never match the type.

Pattern:
true

Type:
{:failure, binary()}

Here is the line it is referencing:

This is calling another function that looks like

  @spec server_allows_join?(T.userid(), integer(), String.t() | nil) ::
          {:failure, String.t()} | true
  def server_allows_join?(userid, lobby_id, password \\ nil) do
    lobby = get_lobby(lobby_id)
    user = Account.get_user_by_id(userid)

    # In theory this would never happen but it's possible to see this at startup when
    # not everything is loaded and ready, hence the case statement
    {consul_response, consul_reason} =
      case Coordinator.call_consul(lobby_id, {:request_user_join_lobby, userid}) do
        {a, b} ->
          {a, b}

        nil ->
          {true, nil}

        v ->
          Logger.error("ConsulServer can_join? error, response #{Kernel.inspect(v)}")
          {false, "ConsulServer error on can_join? call"}
      end

    ignore_password =
      Enum.any?([
        CacheUser.is_moderator?(user),
        Enum.member?(user.roles, "Caster"),
        consul_reason in [:override_approve, :allow_friends]
      ])

    ignore_locked =
      Enum.any?([
        CacheUser.is_moderator?(user),
        Enum.member?(user.roles, "Caster"),
        consul_reason == :override_approve
      ])

    cond do
      user == nil ->
        {:failure, "You are not a user"}

      lobby == nil ->
        {:failure, "No lobby found (type 1, lobby is nil for server_allows_join?)"}

      lobby.locked == true and ignore_locked == false ->
        {:failure, "Battle locked"}

      lobby.password != nil and password != lobby.password and not ignore_password ->
        {:failure, "Invalid password"}

      consul_response == false ->
        {:failure, consul_reason}

      CacheUser.is_restricted?(user, ["All lobbies", "Joining existing lobbies"]) ->
        {:failure, "You are currently banned from joining lobbies"}

      true ->
        true
    end
  end

It seems like this function can return true so not sure what’s going on.

I believe that dialyzer is saying that Account.get_user_by_default can never return anything that isn’t covered by the prior clauses of the cond expression.

Dialyzer is saying it can never reach the true clause of the cond - that the other clauses exhaustively covers what it believes it will see.

Not sure if it’s directly causing the failure you’re seeing, but some of the functions in CacheUser are incorrectly typed. For instance, is_restricted?:

The first argument is typed as T.userid() | T.user(), but there are heads for T.userid() | T.user() | nil.

The second argument is typed as String.t() but there are also heads that support list(String.t())

1 Like

That worked! Thanks.