Fl4m3Ph03n1x
Dialyzer giving warnings that make no sense
Background
I have recently started trying out dialyxir. After playing around with a few pet projects I decided to up the game and try it into something more real.
Problem
However, dialyxir is giving me warnings that make no sense whatsoever. Thanks to the success algorithm dialyzer uses, I would expect it to not find every possible error which is fine, but giving me so many false positives ( which should be impossible ) is definitely something I was not expecting - it completely ruins the experience with noisy warnings that are useless.
Have a look on the following behaviour:
defmodule MyApp.Web.MetricsInstrumenter do
@moduledoc """
Adds HTTP related metrics for every request.
See used Prometheus.PlugPipelineInstrumenter module for details.
"""
use Prometheus.PlugPipelineInstrumenter
end
This created the following dialyxir warning:
lib/myapp/web/metrics_instrumenter.ex:6:guard_fail
Guard test:
tuple_size(_ :: Exception.t())
can never succeed.
This is mind blowing. This makes no sense whatsoever. There is literally only 1 line of code and that line doesn’t even have a when clause.
Why am I getting this error?
Questions
I keep thinking this is a configuration problem. Somehow, I am not configuring the app correctly in the mix.exs file while using Prometheus.
defmodule MyApp.MixProject do
@moduledoc false
use Mix.Project
def project do
[
app: :myaap,
version: "1.1.0",
elixir: "~> 1.7",
elixirc_paths: elixirc_paths(Mix.env()),
start_permanent: Mix.env() == :prod,
deps: deps()
]
end
def application do
[
extra_applications: [:logger],
mod: {MyApp.Application, []}
]
end
defp deps do
[
{ :plug, "~> 1.0" },
{ :prometheus_plugs, "~> 1.1.5" },
{ :prometheus_ex, "~> 3.0" },
{ :dialyxir, "~> 1.0.0-rc.4", only: [:dev], runtime: false }
]
end
defp elixirc_paths(:test), do: ["lib", "test/support"]
defp elixirc_paths(:dev), do: ["lib", "test/support"]
defp elixirc_paths(_), do: ["lib"]
end
But nothing I do works.
Why am I getting these non nonsensical errors?
Marked As Solved
NobbZ
Its already reported and closed:
I’m not sure though, if the fix is in the 1.7 branch or only for 1.8.
Also Liked
NobbZ
Thats hard to tell from this perspective, but probably something in prometheus is faulty?
In general it makes totally sense that tuple_size/1 called with an exception as argument would not suceed. Problem is though, I can not find any reference to tuple_size/1 in either prometheus_plugs, nor prometheus_ex.
So this problem might be burried even deeper.
edit
Can’t even find tuple_size it in the underlying erlang library. I’m trying to dig into this locally. Dialyzer is building its PLT right now…
Fl4m3Ph03n1x
@NobbZ Just to make it clear, I truly appreciate all the help you are giving. Without you this forum wouldn’t be what it is today.
Thank you.
On a separate note, if this is an issue with Prometheus, what are the options?
- make a PR to fix it?
- ask dialyzer to ignore prometheus_ex ? ( not sure if even possible )
NobbZ
Spoiler warning… I sshd into my system at home which runs 1.7/21. It triggers the same errors as you report. Ill have to play a bit with versions to learn more…
NobbZ
This seems to happen in the expansion of Prometheus.Error.with_prometheus_error/1, as the same messages appear when I run dialyzer in the prometheus_ex code base at places where that macro is used:
lib/prometheus/format/protobuf.ex:13: Guard test tuple_size(__@5::#{'__exception__':='true', '__struct__' :=_, _=>_}) can never succeed
lib/prometheus/format/protobuf.ex:21: Guard test tuple_size(__@5::#{'__exception__':='true', '__struct__' :=_, _=>_}) can never succeed
lib/prometheus/format/text.ex:26: Guard test tuple_size(__@5::#{'__exception__':='true', '__struct__':=_, _=>_}) can never succeed
lib/prometheus/format/text.ex:34: Guard test tuple_size(__@5::#{'__exception__':='true', '__struct__':=_, _=>_}) can never succeed
The output is from dialyxir ~> 0.5.0, as that is the specified dependency of prometheus_ex.
As in that macro some testing about the availability of __STACKTRACE__ is done, I have to assume this is due changes in OTP 21 (or has it been in 20?) and exception handling. This is definitifely something that needs to be reported at prometheus.ex.
NobbZ
Its even worse and I will prepare a bug report to elixir, as I can reproduce the issue with the following minimal module:
defmodule Foobar do
def hello do
try do
IO.puts("foo")
rescue
e in ErlangError ->
:error
end
end
end







