Fixing the “Already Initialized Constant Net::ProtocRetryError” Warning in Ruby

If you’ve encountered the following warning in your Ruby code:
/ruby-2.x.x/lib/ruby/2.x.x/net/protocol.rb:66: warning: already initialized constant Net::ProtocRetryError
then you’re dealing with a conflict between different versions of Ruby’s net-protocol
library. This issue occurs when multiple versions of the net-http library are loaded simultaneously:
- The standard library (
stdlib
) version:net/http
- The gemified version:
net-http
Its really not complex, but quite interesting. Let’s dive in.
Understanding the Issue
In my case, the faraday-net_http
gem, which adapts net/http
for Faraday, was loading net/http from the Ruby stdlib.
Upon bundle open faraday-net_http
:
1
2
3
# lib/faraday/adapter/net_http.rb:8
require 'net/http' # this causes the issue
However, in your case, it might be a different gem that triggers the conflict, depending on which libraries or dependencies your application is using.
Starting with Ruby 2.5, parts of the standard library began to be gemified, and by Ruby 3.0, net-http
and net-protocol
were available as standalone gems.
And this is where our issue lies — prior to version 3.0, Ruby by default loads the stdlib version of net/http, which internally requires the stdlib version of net/protocol.
Meanwhile, net-imap
, which was updated to declare net-protocol
as a dependency, requires the gemified version of net-protocol
. This leads to a conflict where both the stdlib and gemified versions of net-protocol
are loaded at the same time.
The warning about “already initialized constant Net::ProtocRetryError” happens when multiple versions of the net-protocol library are loaded simultaneously. This typically occurs when:
net/http
from Ruby’s stdlib is required.net-imap
gem, which now depends on the gemified version ofnet-protocol
, is also loaded.
The Solution
To resolve the conflict, I explicitly added the gemified net-http
to my Gemfile:
1
gem 'net-http'
This forces Bundler to load the gemified version of net-http (and, by extension, the gemified version of net-protocol), ensuring that the correct version is loaded first. Here’s how this solves the problem:
-
Before: The standard library version of
net/http
loaded the stdlib version ofnet-protocol
, and then net-imap loaded the gemified version ofnet-protocol
, causing the “already initialized constant” warning. -
After: Bundler now loads the gemified version of
net-http
, ensuring that the gemifiednet-protocol
is loaded first, preventing the conflict and eliminating the warning.
Why This Works
By explicitly specifying net-http
in the Gemfile, Bundler is directed to load the gem version rather than the standard library version of net/http
. Since the gemified version includes all the necessary dependencies (including net-protocol
), this resolves any conflicts between the stdlib and gem versions.
Keep in Mind
Pinning the net-http
gem in the Gemfile will also add its dependent uri
gem to your lockfile. So, make sure that your Bundler version is compatible with the uri
version associated with the latest or chosen version of net-http
you’re adding to your Gemfile. Also, ensure that your Bundler version is consistent across all environments (development as well as production).
We faced the following issue while deploying to the production environment after pinning net-http
:
You have already activated uri 0.10.0
, but your Gemfile requires uri 0.13.1
.
Since uri
is a default gem, you can either remove your dependency on it or try
updating to a newer version of bundler that supports uri
as a default gem.
Since this is just a temporary solution while upgrading to Ruby 3, we chose to pin the gem uri
to version 0.10.0
:
1
2
gem 'net-http'
gem 'uri', '0.10.0'
Conclusion
If you’re facing the “already initialized constant Net::ProtocRetryError” warning, it’s likely due to a conflict between the stdlib and gemified versions of net-protocol
. By adding net-http
to your Gemfile, you can ensure that Bundler loads the correct gemified version, resolving the issue and keeping your application running smoothly.
While this fix resolves the issue temporarily, the long-term solution is to upgrade to Ruby 3, where Bundler better manages gemified libraries and avoids such conflicts.
If you wish to investigate furthur, you can find the original thread here.
I hope you found this post helpful, or at the very least interesting! Your feedback is always welcome, as I’m committed to improving with every piece I write. See you next week!