Dependency error: Phoenix with gun

I am new to phoenix and want to use it with gun to subscribe to websockets. But when I try this in a phoenix project, I get a dependency error. As a minimal example do the following:

$ mix phx.new --version
Phoenix v1.5.3
$ mix phx.new test --no-ecto
[...]

Then I add gun to the dependencies:

  defp deps do
    [
      {:phoenix, "~> 1.5.3"},
      {:phoenix_html, "~> 2.11"},
      {:phoenix_live_reload, "~> 1.2", only: :dev},
      {:phoenix_live_dashboard, "~> 0.2.0"},
      {:telemetry_metrics, "~> 0.4"},
      {:telemetry_poller, "~> 0.4"},
      {:gettext, "~> 0.11"},
      {:jason, "~> 1.0"},
      {:plug_cowboy, "~> 2.0"},
      {:gun, "~> 1.3.2"},
    ]
  end

But when I do mix deps.get I get the following error:

Resolving Hex dependencies...

Failed to use "cowlib" because
  gun (version 1.3.2) requires ~> 2.6.0
  mix.lock specifies 2.9.1

** (Mix) Hex dependency resolution failed, change the version requirements of your dependencies or unlock them (by using mix deps.update or mix deps.unlock). If you are unable to resolve the conflicts you can try overriding with {:dependency, "~> 1.0", override: true}

What should I do? Thanks in advance.

You can probably unlock cowlib and do a mix deps.get again and it should resolve. Unless you really have some code depending on cowlib > 2.6.

1 Like

Thank you but how exactly can I unlock something? I have never done that before.

And is this a bug? Or how would you use pheonix with gun?

This is not a bug. You installed phoenix, which then fetched the latest version of cowlib and locks the version in mix.lock (this happens for all your dependencies). gun however needs an earlier version of cowlib. You’re however unlikely to be using cowlib directly (transitive dependency) and it seems non of your direct dependencies actually conflicts with the version constraint of gun, so you should be able to safely do mix deps.unlock cowlib, mix deps.get. This will remove the lock on the currently installed version of cowlib and allow mix to resolve the selected version under those new constraints with gun.

2 Likes

OK thanks for the explanation. But it now produces a slightly different error for the minimal example from the beginning ot this thread (the 2.6.0 is green and the 2.9.1 red now)

$ mix deps.unlock cowlib
$ mix deps.get
Resolving Hex dependencies...

Failed to use "cowlib" (version 2.6.0) because
  cowboy (version 2.8.0) requires ~> 2.9.1
  gun (version 1.3.2) requires ~> 2.6.0

** (Mix) Hex dependency resolution failed, change the version requirements of your dependencies or unlock them (by using mix deps.update or mix deps.unlock). If you are unable to resolve the conflicts you can try overriding with {:dependency, "~> 1.0", override: true}

Does it have to do something with Mix phx.new deps error - cowlib - the dependency does not match the requirement ?

Ok, seems like there’s no version of phoenix 1.5, which depends on a cowboy/cowlib low enough to fulfill gun’s requirement. You could try to set the cowlib version in your mix.exs with override: true, but I’m not sure how much cowlib has changed.

Maybe I am wrong but does this mean that gun is outdated and should not depend on old cowlib, i.e. one (=the maintainers of gun) should release a new version of gun to resolve this issue?

I will try to override cowlib to a lower version.

Essentially you’re correct. The changes for http -> http2 (and upcoming http3) did result in a bunch of updates on the cowboy/cowlib site of things and gun wasn’t updated. There seems to be work for gun 2.0 on github though.

1 Like

So now I have

  defp deps do
    [
      {:phoenix, "~> 1.5.3"},
      {:phoenix_html, "~> 2.11"},
      {:phoenix_live_reload, "~> 1.2", only: :dev},
      {:phoenix_live_dashboard, "~> 0.2.0"},
      {:telemetry_metrics, "~> 0.4"},
      {:telemetry_poller, "~> 0.4"},
      {:gettext, "~> 0.11"},
      {:jason, "~> 1.0"},
      {:plug_cowboy, "~> 2.0"},
      {:cowlib, "~> 2.6.0", override: true},
      {:gun, "~> 1.3.2"},
    ]
  end

And it seems to work:

$ mix deps.get
Resolving Hex dependencies...
Dependency resolution completed:
Unchanged:
  cowboy 2.8.0
  file_system 0.2.8
  gettext 0.18.0
  jason 1.2.1
  mime 1.3.1
  phoenix 1.5.3
  phoenix_html 2.14.2
  phoenix_live_dashboard 0.2.6
  phoenix_live_reload 1.2.4
  phoenix_live_view 0.13.3
  phoenix_pubsub 2.0.0
  plug 1.10.3
  plug_cowboy 2.3.0
  plug_crypto 1.1.2
  ranch 1.7.1
  telemetry 0.4.2
  telemetry_metrics 0.5.0
  telemetry_poller 0.5.1
New:
  cowlib 2.6.0
  gun 1.3.2
* Updating cowlib (Hex package)
* Getting gun (Hex package)
$ mix compile
===> Compiling cowlib
===> Compiling cowboy
===> Compiling gun
==> plug_cowboy
Compiling 6 files (.ex)
Generated plug_cowboy app
==> phoenix
Compiling 66 files (.ex)
Generated phoenix app
==> phoenix_live_reload
Compiling 4 files (.ex)
Generated phoenix_live_reload app
==> phoenix_live_view
Compiling 18 files (.ex)
Generated phoenix_live_view app
==> phoenix_live_dashboard
Compiling 33 files (.ex)
Generated phoenix_live_dashboard app
==> test
Compiling 13 files (.ex)
Generated test app

But can this override cause any problems? Or am I on the safe side whenever it compiles as it apparently did?

Yes. Cowlib could work differently than gun expects, and there can be bugs at runtime. It is quite possible that it isn’t possible to use Phoenix 1.5 and gun 1.3 together at all.

1 Like

Too bad. But is there a way of using two versions of cowlib at the same time, one for gun 1.3 and another for Phoenix 1.5?

No, that is not possible, Elixir can only load one version of code for a given application. However you may be in luck, it looks like the version of gun on github supports the latest cowlib. You could try doing:

 {:gun, github: "ninenines/gun"},
2 Likes

I started freash again with the minimal example and put

  defp deps do
    [
      {:phoenix, "~> 1.5.3"},
      {:phoenix_html, "~> 2.11"},
      {:phoenix_live_reload, "~> 1.2", only: :dev},
      {:phoenix_live_dashboard, "~> 0.2.0"},
      {:telemetry_metrics, "~> 0.4"},
      {:telemetry_poller, "~> 0.4"},
      {:gettext, "~> 0.11"},
      {:jason, "~> 1.0"},
      {:plug_cowboy, "~> 2.0"},
      {:gun, github: "ninenines/gun"}
    ]
  end

in mix.exs but then I get

$ mix deps.get
* Getting gun (https://github.com/ninenines/gun.git)
remote: Enumerating objects: 59, done.        
remote: Counting objects: 100% (59/59), done.        
remote: Compressing objects: 100% (36/36), done.        
remote: Total 2990 (delta 12), reused 45 (delta 9), pack-reused 2931        
Empfange Objekte: 100% (2990/2990), 1.22 MiB | 285.00 KiB/s, Fertig.
Löse Unterschiede auf: 100% (1841/1841), Fertig.
* Getting cowlib (https://github.com/ninenines/cowlib)
remote: Enumerating objects: 74, done.        
remote: Counting objects: 100% (74/74), done.        
remote: Compressing objects: 100% (57/57), done.        
remote: Total 1617 (delta 20), reused 52 (delta 11), pack-reused 1543        
Empfange Objekte: 100% (1617/1617), 978.08 KiB | 0 bytes/s, Fertig.
Löse Unterschiede auf: 100% (1057/1057), Fertig.
Resolving Hex dependencies...
Dependency resolution completed:
Unchanged:
  cowboy 2.8.0
  cowlib 2.9.1
  file_system 0.2.8
  gettext 0.18.0
  jason 1.2.1
  mime 1.3.1
  phoenix 1.5.3
  phoenix_html 2.14.2
  phoenix_live_dashboard 0.2.6
  phoenix_live_reload 1.2.4
  phoenix_live_view 0.13.3
  phoenix_pubsub 2.0.0
  plug 1.10.3
  plug_cowboy 2.3.0
  plug_crypto 1.1.2
  ranch 1.7.1
  telemetry 0.4.2
  telemetry_metrics 0.5.0
  telemetry_poller 0.5.1
Dependencies have diverged:
* cowlib (https://github.com/ninenines/cowlib)
  different specs were given for the cowlib app:

  > In deps/gun/rebar.config:
    {:cowlib, ~r/.*/, [env: :prod, override: true, git: "https://github.com/ninenines/cowlib", ref: "2.9.0"]}

  > In deps/cowboy/rebar.config:
    {:cowlib, "~> 2.9.1", [env: :prod, hex: "cowlib", repo: "hexpm", optional: false]}

  Ensure they match or specify one of the above in your deps and set "override: true"
** (Mix) Can't continue due to errors on dependencies
$ mix deps.unlock cowlib
$ mix deps.get
* Updating cowlib (https://github.com/ninenines/cowlib)
Resolving Hex dependencies...
Dependency resolution completed:
Unchanged:
  cowboy 2.8.0
  file_system 0.2.8
  gettext 0.18.0
  jason 1.2.1
  mime 1.3.1
  phoenix 1.5.3
  phoenix_html 2.14.2
  phoenix_live_dashboard 0.2.6
  phoenix_live_reload 1.2.4
  phoenix_live_view 0.13.3
  phoenix_pubsub 2.0.0
  plug 1.10.3
  plug_cowboy 2.3.0
  plug_crypto 1.1.2
  ranch 1.7.1
  telemetry 0.4.2
  telemetry_metrics 0.5.0
  telemetry_poller 0.5.1
New:
  cowlib 2.9.1
Dependencies have diverged:
* cowlib (https://github.com/ninenines/cowlib)
  different specs were given for the cowlib app:

  > In deps/gun/rebar.config:
    {:cowlib, ~r/.*/, [env: :prod, override: true, git: "https://github.com/ninenines/cowlib", ref: "2.9.0"]}

  > In deps/cowboy/rebar.config:
    {:cowlib, "~> 2.9.1", [env: :prod, hex: "cowlib", repo: "hexpm", optional: false]}

  Ensure they match or specify one of the above in your deps and set "override: true"
** (Mix) Can't continue due to errors on dependencies
peter@ux550vdp:~/tmpdir/test$ ls
assets  _build  config  deps  lib  mix.exs  mix.lock  priv  README.md  test
$ vim mix.exs 

I then tried

  defp deps do
    [
      {:phoenix, "~> 1.5.3"},
      {:phoenix_html, "~> 2.11"},
      {:phoenix_live_reload, "~> 1.2", only: :dev},
      {:phoenix_live_dashboard, "~> 0.2.0"},
      {:telemetry_metrics, "~> 0.4"},
      {:telemetry_poller, "~> 0.4"},
      {:gettext, "~> 0.11"},
      {:jason, "~> 1.0"},
      {:plug_cowboy, "~> 2.0"},
      {:cowlib, "~> 1.9.0", override: true},
      {:gun, github: "ninenines/gun"}
    ]
  end

to fix cowlib the lower version of the two (2.9.1 and 2.9.0) as before, where it had worked (2.6.0):

$ mix deps.get
** (Mix) No matching version for cowlib ~> 1.9.0 (from: mix.exs) in registry

The latest version is: 2.9.1

If there is an obvious mistake that I have made then please tell me but I think you already helped me a lot and I consider this as suffifiently solved (i.e. that the reason is outdated latest version of gun in hex.pm). Both of you, thank you very much.

Ah sorry, I have spotted it myself: 2.9.0 as override works:

$ mix deps.get
Resolving Hex dependencies...
Dependency resolution completed:
Unchanged:
  cowboy 2.8.0
  cowlib 2.9.1
  file_system 0.2.8
  gettext 0.18.0
  jason 1.2.1
  mime 1.3.1
  phoenix 1.5.3
  phoenix_html 2.14.2
  phoenix_live_dashboard 0.2.6
  phoenix_live_reload 1.2.4
  phoenix_live_view 0.13.3
  phoenix_pubsub 2.0.0
  plug 1.10.3
  plug_cowboy 2.3.0
  plug_crypto 1.1.2
  ranch 1.7.1
  telemetry 0.4.2
  telemetry_metrics 0.5.0
  telemetry_poller 0.5.1
* Updating cowlib (Hex package)

So it is still an override and might cause runtime errors but the risk is much smaller since the versions are both 2.9.* right?

2 Likes

That is correct, I’m pretty sure that should work fine.

Problem here is {:cowlib, "~> 1.9.0", override: true},, there is 1.9.0 but it should be 2.9.0 I think.

2 Likes

Even if that works now you should still not rely on it. A few commits in the future and who knows?

Better find the latest commit hash in the gun repo that works for you now and pin the dependency on it:

      {:gun, github: "ninenines/gun", ref: "921c47146b2d9567eac7e9a4d2ccc60fffd4f327"}

That way, if you can’t rely on a tag or a branch, at least you can lock on a particular commit until you’re comfortable to upgrade the library dependency again in the future.

Mix automatically locks to git commits.

2 Likes

Yes, but on non-caching CI/CD the next build will happily pull a version of the dependency that’s not the same as the one on the devs’ machines. That can break tests. Seen it happen, too many times.

1 Like

I’m pretty sure that would only happen if you don’t commit your mix.lock file which you almost always should commit for elixir projects.

3 Likes