Dialyzer seems not to expect System.cmd to return a non-zero code

I ran dialyzer on this new code (with both Elixir 1.7 and 1.12) and am getting the error:

The pattern
variable_error

can never match, because previous clauses completely cover the type
:ok.

It points at the line in maybe_gen_certificates that does the put_error. I don’t understand why. The spec for generate_certificates should be correct, specifying :ok | {atom(), atom()}, and the with statement should be able to fail with {_, non_zero_integer} and return that as response. What am I missing?

  defp maybe_gen_certificates(config, false) do
    case generate_certificates() do
      :ok -> config
      error -> put_error(config, :certificate, error)
    end
  end

  @spec generate_certificates() :: :ok | {atom(), atom()}
  def generate_certificates do
    {key, cert} = keys()

    write_keys_permissions({key, cert})

    response =
      with {_, 0} <- System.cmd("openssl", ~w(genrsa -out #{key} 2048)),
           {_, 0} <- System.cmd("openssl", ~w(rsa -in #{key} -out #{cert} -outform PEM -pubout)),
           do: :ok

    reset_keys_permissions({key, cert})
    response
  end

Thanks! :smiley:

System.cmd and therefore generate_certificates returns {Collectable.t(), exit_status :: non_neg_integer()} not {atom(), atom()} in the case of a non zero exit status.

That worked. Thanks.

I wonder why this doesn’t report that the spec doesn’t match the success typing of the function. That would have pointed me directly to the problem. I would think that if it was smart enough to know that the failure couldn’t actually return {atom, atom} that it would complain about what it should be returning. Or even recognize that there was a second option for return that the error would catch.