Dialyzer: no local return : Ecto.Repo.get_by/3

Dialyzer complains about this below:

lib/my_app/accounts/accounts.ex:134: Function authenticate_by_username_password/2 has no local return

def authenticate_by_username_password(username, given_password) do
  user = User
    |> Repo.get_by(username: username)
    |> Repo.preload(:credential)

  cond do
    user && checkpw(given_password, user.credential.password_hash) ->
      {:ok, user}
    user ->
      {:error, :unauthorized}
    true ->
      dummy_checkpw()
      {:error, :not_found}
  end
end

As mentioned in the doc If the struct in the queryable has no or more than one primary key, it will raise an argument error.

Moreover, the return value of get_by/3 could be :

Ecto.Schema.t() |
nil |
no_return()

Does that mean that if an argument error is raised by get_by/3, then the cond block won’t be executed, moreover authenticate_by_username_password/2 return value will be set to type no_return(), which finally makes dialyzer complain like that?

If so, should I try to catch the possible argument error of get_by/3? Or just let it go :wink:.

Tks,
germain

I’m terrible at Dialyzer but…

  1. Yes, any exception anywhere that isn’t rescued will result in a non-local return. But thats ok if you have described none() or no_return() in the @spec for your function.

  2. Do you have a @spec for the function? Since Dialyzer is a “success typing” tool it helps if it knows your intention.

  3. Are you also getting Dialyzer warnings on checkpw and dummy_checkpw?

  1. I have added the spec below but I am still getting the warning.
    @spec authenticate_by_username_password(String.t(), String.t()) :: {:ok, Ecto.Schema.t()} | {:error, atom()} | no_return()

  2. I have just added it.

  3. No warning on checkpw and dummy_checkpw.

Are there no dialyzer errors in related code at all?

The fact that the Ecto function can raise in some cases shouldn’t matter, when Dialyzer says “no local return” it means none at all. Here I would suspect something is wrong with checkpw.

1 Like

Hi Kip,

I’m having the “ElixirLS Dialyzer] Function get_access_token/2 has no local return” warning in a function that uses checkpw.

Since you mentioned in No. 3 on you list I thought you might have a fix for the warning … do you ?

I do assume you use comeonin with argon2_elixir prior to version 1.3.1? If this is true, please update argon to 1.3.1 and check if the problem persists. It had a bug discussed in #13 which I submitted a fix in #21.

If my assumptions are all wrong, you need to provide more details, as used packages, their versions and probably some bit of code where the warning occurs.

Also due to some problems with elixir LS (it has problems to rebuild typeinfo of deps when necessary or update in dependent files) so to be sure either run dialyxir from the shell or remove your elixir-ls folder and restart the editor (to make the LS restart).

3 Likes

Thanks for your input and suggestions @NobbZ,

Right now I’m on some frontend (React+Relay) issues but as soon as I get back to backend I’ll start applying what you’ve said.

Hello again and sorry for taking too long to reply.

Your assumptions were correct @NobbZ … I’ve updated argon2_elixir to 1.3.1 and now the warnings are all gone.

Thank you very much

If you mark @NobbZ’s answer as the solution, it will help others coming across the same problem.

I don’t see the option to mark the answer as the solution.

@hisa You can’t, only the topic creator or moderators can… It would be a button with a check in it.