Search code examples
ruby-on-railsrubyrubygemsbundler

Why is bundler putting apparently-incorrect gems in my Gemfile.lock?


I have a gemfile making no reference to the 'mail' gem, 'net-pop', 'net-imap', or 'net-protocol'.

The installed application versions are:

  • rbenv 1.1.2
  • Ruby 2.6.1p33
  • Rails 6.0.6.1
  • rubygems 3.4.4

When I execute the 'rails' binary (e.g. 'rails db:create'), I get warnings about already-defined constants:

home/alexander/.rbenv/versions/2.6.1/lib/ruby/2.6.0/net/protocol.rb:66: warning: already initialized constant Net::ProtocRetryError
/home/alexander/.rbenv/versions/2.6.1/lib/ruby/gems/2.6.0/gems/net-protocol-0.2.1/lib/net/protocol.rb:68: warning: previous definition of ProtocRetryError was here
/home/alexander/.rbenv/versions/2.6.1/lib/ruby/2.6.0/net/protocol.rb:206: warning: already initialized constant Net::BufferedIO::BUFSIZE
/home/alexander/.rbenv/versions/2.6.1/lib/ruby/gems/2.6.0/gems/net-protocol-0.2.1/lib/net/protocol.rb:214: warning: previous definition of BUFSIZE was here
/home/alexander/.rbenv/versions/2.6.1/lib/ruby/2.6.0/net/protocol.rb:503: warning: already initialized constant Net::NetPrivate::Socket
/home/alexander/.rbenv/versions/2.6.1/lib/ruby/gems/2.6.0/gems/net-protocol-0.2.1/lib/net/protocol.rb:541: warning: previous definition of Socket was here

The gem net-protocol is not referenced directly in my Gemfile but it does appear in Gemfile.lock:

mail (2.8.0.1)
  mini_mime (>= 0.1.1)
  net-imap
  net-pop
  net-smtp
marcel (1.0.2)
matrix (0.4.2)
method_source (1.0.0)
mini_mime (1.1.2)
mini_portile2 (2.8.1)
minitest (5.17.0)
msgpack (1.6.0)
nested_form (0.3.2)
net-imap (0.3.4)
  date
  net-protocol
net-pop (0.1.2)
  net-protocol
net-protocol (0.2.1)
  timeout
net-scp (4.0.0)
  net-ssh (>= 2.6.5, < 8.0.0)
net-smtp (0.3.3)
  net-protocol

I found a discussion indicating that the above warnings stem from Ruby removing some functionality out of the standard library for Rails 7/Ruby 3: Warnings when upgrading application from Rails 5 to Rails 7

However I'm using Rails 6 (and ruby 2.6.1), not 7, but I suppose that it's possible the change actually happened from 5 to 6.

Anyway, the main question is: why am I ending up with gems in my Gemfile.lock which a) aren't explicitly called out in Gemfile, b) don't appear to be dependencies of any of my gems in Gemfile, c) aren't fully compatible with my version of ruby?

It seems like some package-manager (rubygems? bundler?) is pulling in a version of net-protocol (or something like that) which isn't exactly compatible or intended to be used with my ruby version.


Edit

It appears that net-protocol is pulled into Gemfile.lock because of net-imap, which is pulled in by mail, which is pulled in by actionmailbox.

Part of my confusion was happening because I thought Gemfile.lock listed dependencies entirely in tree-form, which appears not to be the case. It's only one-level trees for a single gem.

Anyway, there is still the remaining question: why is bundler brining in a version of net-protocol which is not compatible with the rest of my environment?


Solution

  • This issue is fully explained here: https://github.com/rails/rails/pull/44083

    And partially addressed here: https://github.com/ruby/net-protocol/issues/10

    Quote:

    It's getting loaded twice because the net-http that ships with Ruby 2.7 has a require_relative "protocol" that causes it to always load the library in Ruby instead of the gem. By using the net-http gem as well, we avoid this problem.

    My rough understanding is that some aspects of the bundler/rubygems/rails ecosystem have incompatibility issues which have not been resolved at the package-manager level.

    The workaround is to put net-http into your gemfile, which causes bundler to ensure that a valid version of net-protocol or whatever other dependency is used. Otherwise, bundler will get a version of net-protocol which isn't compatible with ruby version 2.7 or lower.

    It appears to me that this is a consequence of using particular versions of ruby together with particular versions of rails, and nothing project-specific.