Unknown type ranch:ref/0 dialyzer warning in cowboy_req on Erlang/OTP 26

Hello, I’m seeing 2 new dialyzer warnings in my app that uses cowboy on 26.0 that weren’t there on 25.3:

_build/default/lib/cowboy/src/cowboy_req.erl
Line 134 Column 9: Unknown type ranch:ref/0
Line 152 Column 18: Unknown type ranch_proxy_header:proxy_info/0

It’s using cowboy 2.10.0 which I believe uses ranch 1.8.0. In the case of ranch:ref/0 I can indeed see that cowboy_req references ranch:ref/0 and ranch defines and exports it. So shouldn’t it keep working?

Has anyone seen and resolved the issue?

Here’s a run with the issue Remove rinseweb_wiz:answer/1 which should no longer be used · RinseOne/rinseweb@f706757 · GitHub

Digging further into this, I see that with the Erlang/OTP 26 a new version of Dialyzer 5.1 was released. According to its release notes a backward incompatible change was introduced to enable unknown option by default.

Dialyzer has enabled (by default) warnings about unknown types and functions.

Prior to this change, Dialyzer had warnings about unknown types and functions disabled (by default).

This default value has been overwritten; Dialyzer now warns about unknown types and functions (as requested by the community in GH-5695).

So it seems like the options are

  1. Add Dialyzer option no_unknown to the project to disable the unknown types and functions checks to restore previous behavior.
  2. Manually add problematic dependencies that aren’t automatically included in the PLT such as {plt_extra_apps, [ranch]}.
  3. Add Dialyzer option {plt_apps, all_deps} to the project.

I would like to take advantage of the new default, so I’m not inclined to do (1), but it’s interesting that the default behavior was changed that might seemingly result in violation of the principle of the least astonishment.

So, assuming the above assessment is correct, is (2) or (3) or another I don’t know about the recommended path forward?

1 Like

Assuming you want as much automatic checking as possible, I’d say your options are (2) and:

(4) Add missing type definitions and/or exports where needed.

I recently had the exact same issue you reported here, except with use of file:position/0 which is documented but wasn’t exported for unclear reasons. I ended up submitting a PR to fix that (file: export location/0 type by mikpe · Pull Request #7486 · erlang/otp · GitHub).

1 Like

Thanks for the reply. In this case, the type definitions and exports are already there, as I linked them in the original post. The problem seems to be that Dialyzer doesn’t seem to know which apps need to be in the PLT (2nd level dependencies?) and their absence is exposed via the warnings produced due to making the unknown check on by default. In fact, I’m actually not sure why I only see the 2 warnings I reported and not many many more. Part of me suspects there’s a subtle bug somewhere but :person_shrugging:.

I’m also inclined to go with option (2) just because, at least in my case, the project is small enough that I can take it on case by case basis, and option (3) makes the check take noticeably, like 7x, longer time.

I would be interested in (5) make {dialyzer, [{plt_apps, all_deps}]} the default. As it stands now, including cowboy in a Erlang 26 project and running Dialyzer will show this warning by default which is a bit weird?

It has always been more astonishing to me that unknown was off by default :slight_smile:.

Agreed. :smile:

I ended up submitting a PR to fix that…

Yup, same for me, for binary:part/0, and I expect others to show up in the near future (which is actually improving the API).

:wave:

I think an alternative (at the OTP level) would be for Dialyzer to not “dig so deep”. If I only consume cowboy, why would I need warnings about ranch? (but I’m surely missing some detail on how OTP does the gathering of modules to analyse)

I do agree, though, that adding {plt_extra_apps, [ranch]} is not a proper solution, per what I just wrote, but I think making the default all_deps is maybe a bit much (?)

I think that wouldn’t work, if a dependency has an exported type that depends on another exported type from a sub-dependency (as I suspect is the case with Cowboy currently). The only way to solve this for all possible dependencies is include all dependencies in the analysis (otherwise Dialyzer wouldn’t have the complete picture).

That being said, I wonder why there is no {analyzed_apps, [...]} setting, which I guess should default to only the apps in the project…

It’s not a warning about ranch per se, it’s a warning saying that dialyzer doesn’t have a complete picture. Because unknown types and functions are interpreted in the widest possible way (any() everywhere), you might be missing out on pertinent warnings in your code.

1 Like

I understand that bit :grinning:. My thinking was more like “Why isn’t the missing information auto-fetched?” (i.e. what would be required to have plt_extra_apps “filled” automatically?). It’ll always fail, otherwise, and fully analysing dependencies, the better part of which might not benefit the consumer, still feels like overkill…

Or maybe we just need a better error message?

You’re right, for the way I expressed myself initially (thinking out loud), which was wrong. I’d “like” it to be possible to “guess” the missing bits (and “auto-import” those) instead of having to worry about it. Maybe too complicated, maybe not possible at all (?)

On the other hand, I still think there’s a better solution than changing the default: plt_extra_apps, for example, shows it’s possible…

dialyzer doesn’t know that information is missing until it’s been invoked, and has no way to communicate to rebar3 that it needs something from a module that is missing (from its perspective).

It’s definitely possible to solve this but it would make things a lot more complicated than just changing the default for plt_apps to all_deps.

3 Likes