Getting Dialyzer errors: Callback info about the Plug behaviour is not available, and functions 'do not exist'

Hello!

I use elixir with asdf and mix dialyzer emits errors like that:

deps/plug/lib/plug/router.ex:1:callback_info_missing
Callback info about the Plug behaviour is not available.
________________________________________________________________________________
deps/plug/lib/plug/router.ex:234:unknown_function
Function Plug.Router.Utils.decode_path_info!/1 does not exist.
________________________________________________________________________________
deps/plug/lib/plug/router.ex:242:unknown_function
Function :telemetry.span/3 does not exist.
________________________________________________________________________________

I tried this fixes from google:

  • Changing envs (dev/test/no env) when running dialyzer
  • Setting different elixir/erlang versions in .tool-versions
  • Setting elixir version to 1.16.2-otp-26 and erlang to 26.0.1 so they should match
  • Setting plt_apps & plt_add_apps and plt_add_deps: :apps_direct to make dialyzer scan only specified dependencies

But none of that worked. Any ideas on how to fix that errors?
Here is a project where I reproduced things above

Thank you all in advance :raised_hands:

1 Like

Can you also push your dialyzer-ignore.exs in the repo, please? I am taking a look currently.

FYI: I am trying with erlang@27.2 and elixir@1.18.1-otp-27 (I am using mise and not asdf and I strongly suggest you do the same, it slightly improves startup times, also mise is 100% compliant with asdf’s .tool-versions file). Do you get a number of warnings like I do (these happen before the dialyzer warnings you showed)?

:dialyzer.run error: Analysis failed with error:
Could not scan the following file(s):
  Could not get Core Erlang code for: /Users/dimi/.local/share/mise/installs/elixir/1.18.1-otp-27/.mix/archives/hex-2.1.1/hex-2.1.1/ebin/Elixir.String.Chars.Hex.Solver.Term.beam
  Could not get Core Erlang code for: /Users/dimi/.local/share/mise/installs/elixir/1.18.1-otp-27/.mix/archives/hex-2.1.1/hex-2.1.1/ebin/Elixir.String.Chars.Hex.Solver.PackageRange.beam
  Could not get Core Erlang code for: /Users/dimi/.local/share/mise/installs/elixir/1.18.1-otp-27/.mix/archives/hex-2.1.1/hex-2.1.1/ebin/Elixir.String.Chars.Hex.Solver.Constraints.Union.beam
  Could not get Core Erlang code for: /Users/dimi/.local/share/mise/installs/elixir/1.18.1-otp-27/.mix/archives/hex-2.1.1/hex-2.1.1/ebin/Elixir.String.Chars.Hex.Solver.Incompatibility.beam
# ...and many more...

I didn’t put anything special into dialyzer-ignore.exs, just forgot to strip mentions of it from error reproducing repo (NDA stuff).

I see :dialyzer.run error: Analysis failed with error: in some cases, ie changing plt_apps for plt_add_apps and vice versa. Also I see it if key ignore_warnings is missing.

I’ve checked dialyzer with erlang@27.2 and elixir@1.18.1-otp-27, same here.

Mise seems great fit, will use it in future projects :handshake:

I wasn’t able to fix the error, but I was able to move the crash site somewhat: See the bottom for the rest of the story…

  • removed the stray close-square-bracket present in 0b8736d which blocks running any Mix task
  • removed all of the plt_* options from the Dialyzer config
  • remove :mix and :hex from extra_applications - that one in particular silences the Could not get Core Erlang code for: /Users/mattjones/.asdf/installs/elixir/1.16.2-otp-26/.mix/archives/hex-2.1.1/hex-2.1.1/ebin/Elixir.Hex.Crypto.PublicKey.beam chatter before the main Dialyzer results
  • added {:hex_core, "~> 0.11.0"}, to deps
  • updated all the references to :mix_hex_* to instead use the corresponding hex_core modules named :hex_*

This results in a compiler error:

==> dialyzer_error_rep
Compiling 5 files (.ex)
     warning: Hex.Shell.info/1 is undefined (module Hex.Shell is not available or is yet to be defined)
     │
 141 │         Hex.Shell.info("* public key at #{path} does not match private key, overwriting")
     │                   ~
     │
     └─ lib/dialyzer_error_rep/registry_builder.ex:141:19: DialyzerErrorRep.RegistryBuilder.ensure_public_key/2
     └─ lib/dialyzer_error_rep/registry_builder.ex:151:17: DialyzerErrorRep.RegistryBuilder.create_directory/1
     └─ lib/dialyzer_error_rep/registry_builder.ex:158:17: DialyzerErrorRep.RegistryBuilder.write_file/2
     └─ lib/dialyzer_error_rep/registry_builder.ex:161:17: DialyzerErrorRep.RegistryBuilder.write_file/2
     └─ lib/dialyzer_error_rep/registry_builder.ex:168:15: DialyzerErrorRep.RegistryBuilder.remove_file/1

as well as the equivalent Dialyzer error:

lib/dialyzer_error_rep/registry_builder.ex:141:unknown_function
Function Hex.Shell.info/1 does not exist.
________________________________________________________________________________
lib/dialyzer_error_rep/registry_builder.ex:151:unknown_function
Function Hex.Shell.info/1 does not exist.
________________________________________________________________________________
lib/dialyzer_error_rep/registry_builder.ex:158:unknown_function
Function Hex.Shell.info/1 does not exist.
________________________________________________________________________________
lib/dialyzer_error_rep/registry_builder.ex:168:unknown_function
Function Hex.Shell.info/1 does not exist.
________________________________________________________________________________
done (warnings were emitted)
Halting VM with exit status 2

Looking at the definition of Hex.Shell.info/1, it’s a trivial wrapper over Mix.shell().info/1.

Replacing those calls in RegistryBuilder causes Dialyzer to emit a new complaint:

lib/dialyzer_error_rep/registry_builder.ex:141:unknown_function
Function Mix.shell/0 does not exist.
________________________________________________________________________________
lib/dialyzer_error_rep/registry_builder.ex:151:unknown_function
Function Mix.shell/0 does not exist.
________________________________________________________________________________
lib/dialyzer_error_rep/registry_builder.ex:158:unknown_function
Function Mix.shell/0 does not exist.
________________________________________________________________________________
lib/dialyzer_error_rep/registry_builder.ex:168:unknown_function
Function Mix.shell/0 does not exist.
________________________________________________________________________________
done (warnings were emitted)

This can finally be silenced by adding plt_add_apps: [:mix], to the Dialyzer config in mix.exs, producing a clean Dialyzer report!

Generated dialyzer_error_rep app
Finding suitable PLTs
Checking PLT...
[:asn1, :compiler, :cowboy, :cowboy_telemetry, :cowlib, :crypto, :dialyzer_error_rep, :eex, :elixir, :hex_core, :inets, :kernel, :logger, :mime, :mix, :plug, :plug_cowboy, :plug_crypto, :public_key, :ranch, :ssl, :stdlib, :telemetry]
Looking up modules in dialyzer.plt
Finding applications for dialyzer.plt
Finding modules for dialyzer.plt
Checking 852 modules in dialyzer.plt
Adding 95 modules to dialyzer.plt
done in 0m3.48s
ignore_warnings: dialyzer_ignore.exs

Starting Dialyzer
[
  check_plt: false,
  init_plt: ~c"/Users/mattjones/src/dialyzer-unknown-error-rep/dialyzer_cache/dialyzer.plt",
  files: [~c"/Users/mattjones/src/dialyzer-unknown-error-rep/_build/dev/lib/dialyzer_error_rep/ebin/Elixir.DialyzerErrorRep.Application.beam",
   ~c"/Users/mattjones/src/dialyzer-unknown-error-rep/_build/dev/lib/dialyzer_error_rep/ebin/Elixir.DialyzerErrorRep.RegistryBuilder.beam",
   ~c"/Users/mattjones/src/dialyzer-unknown-error-rep/_build/dev/lib/dialyzer_error_rep/ebin/Elixir.DialyzerErrorRep.Router.beam",
   ~c"/Users/mattjones/src/dialyzer-unknown-error-rep/_build/dev/lib/dialyzer_error_rep/ebin/Elixir.DialyzerErrorRep.Static.beam",
   ~c"/Users/mattjones/src/dialyzer-unknown-error-rep/_build/dev/lib/dialyzer_error_rep/ebin/Elixir.HexRegistry.beam"],
  warnings: [:unknown]
]
Total errors: 0, Skipped: 0, Unnecessary Skips: 0
done in 0m1.33s
done (passed successfully)
4 Likes

Got a link to a PR?

1 Like

Thank you for following up. :heart:

I too removed the plt_* clauses when I experimented locally. And I too was convinced I have to put something more in the extra_applications but did not get as far as you.

Can’t comment on the RegistryBuilder module though, I never attempted to use Hex’s API.

Thank you for your time! I was able to fix dialyzer errors in original project and CI as well :raised_hands: