Dialyzer is a great static analysis tool for Erlang and has helped me catch many bugs related to what types I thought I was passing to a function versus what actually gets passed. Some of the errors Dialyzer emits are rather cryptic at first (as seems commonplace in the Erlang language/environment in general) but after you understand the causes of the errors, the fix is easily recognized. My most common error is Dialyzer inferring a different return type that what I put in my -spec, followed by Dialyzer telling me the same function has no local return. An example:

    foo.erl:125: The specification for foo:init/1 states that the function might also return {'ok',tuple()} but the inferred return is none()
    foo.erl:126: Function init/1 has no local return

The init/1 function (for a gen\_server, btw):

    -spec(init/1 :: (Args :: list()) -> tuple(ok, tuple())).
    init(_) ->
      {ok, #state{}}.

And the state record definition:

    -record(state, {
      var_1 = {} :: tuple(string(), tuple())
      ,var_2 = [] :: list(tuple(string(), tuple()))

Spot the error? In the record definition, var\_1 is initialized to an empty tuple and var\_2 is initialized to an empty list, yet the spec typing for the record does not take that into account. The corrected version:

    -record(state, {
      var_1 = {} :: tuple(string(), tuple()) | {}
      ,var_2 = [] :: list(tuple(string(), tuple())) | []

And now Dialyzer stops emitting the spec error and the no local return error.