Error installing rails: net-protocol requires Ruby version >= 2.6.0
Updated on
If you’re trying to install an old version of Rails or actionmailer, such as 4.0.x or 4.1.x, while using a version of Ruby older than 2.6, you probably got one of these errors:
- net-protocol requires Ruby version >= 2.6.0
- timeout requires Ruby version >= 2.6.0
- concurrent-ruby requires Ruby version >= 2.3
- thor requires Ruby version >= 2.6.0
- base64 requires Ruby version >= 2.4
Here are example error messages you might see:
ERROR: Error installing actionmailer:
There are no versions of net-protocol (>= 0) compatible with your Ruby &
RubyGems. Maybe try installing an older version of the gem you're looking for?
net-protocol requires Ruby version >= 2.6.0. The current ruby version is 2.0.0.648.
Or this one complaining about the timeout gem:
ERROR: Error installing actionmailer:
The last version of timeout (>= 0) to support your Ruby & Rubygems was 0.4.0.
Try installing it with `gem install timeout -v 0.4.0` and then running the
current command again.
timeout requires Ruby version >= 2.6.0. The current ruby version is 2.2.0.
Or ones like these while installing Rails:
ERROR: Error installing rails:
There are no versions of net-protocol (>= 0) compatible with your Ruby &
RubyGems. Maybe try installing an older version of the gem you're looking for?
net-protocol requires Ruby version >= 2.6.0. The current ruby version is 2.1.0.
ERROR: Error installing rails:
concurrent-ruby requires Ruby version >= 2.3.
ERROR: Error installing rails:
base64 requires Ruby version >= 2.4.
These types of errors are very common when working with older Ruby projects, and the best solution depends on the context. If I just gave you the solution without explaining how Rails and other Ruby projects work, it won’t really help you the next time you run into this issue.
This might seem like a long post, but it will be worth your time to understand some basic concepts about Ruby gems. Most of these concepts apply whether you’re on macOS, Linux, or Windows. Here’s a table of contents to give you an overview:
- TL;DR
- What are Ruby gems and how do they work?
- What happens when you install a gem
- How gem versioning works
- How to install the right combination of gems
- Installing gems with gem install vs bundle install
- Things to watch out for when using outdated Ruby versions on macOS
TL;DR
Here are the main points from this article:
-
Always use Bundler to install a Ruby project’s dependencies by running
bundle install
-
Ruby versions older than 2.6 don’t include Bundler by default, so you have to figure out the correct Bundler version based on your Ruby version, and then install it before you can run
bundle install
. Ruby on Mac Ultimate automatically installs the correct version of Bundler and Rubygems for you, and it makes it a lot easier to install Ruby versions older than 2.6 on Apple Silicon Macs. -
You don’t need to have Rails installed globally with
gem install rails
in order to run an existing Rails app. After you have the required version of Ruby and Bundler installed, you just need tocd
into the top-level folder of the Rails app, and then runbundle install
. -
bundle install
might not always work depending on your computer’s OS and hardware. For example, some older gem versions are not compatible with Apple Silicon Macs, so you might need to update some gems in your project to newer versions in order to get an old Ruby project up and running. -
All of the above assume you have a proper and working Ruby development environment with a version manager that allows you to install multiple Ruby versions and switch between them. Ruby on Mac makes this super easy.
What are Ruby gems and how do they work?
A gem is a way to package Ruby code so that it can be easily installed on a computer. Some gems act like a plugin that can add functionality to an existing app, such as a Rails app. Other gems, like Rails, are much bigger and can be run on their own.
Many gems are also made up of other gems. These are known as dependencies because the main gem depends on them to work. Without those dependencies, the main gem would not work. To see the dependencies of a particular gem, you can look it up on rubygems.org.
For example, here is the rubygems page for Rails. You can see that the latest version of Rails has 13 main dependencies, but each of those dependencies might have their own dependencies. So, the total number of gems Rails depends on is a lot more than 13.
In addition to depending on specific versions of other gems, many gems also specify which versions of Ruby they support. If you look at the sidebar on the right of the Rails page on rubygems.org, you’ll see that the required Ruby version is at least 2.7.0 for the latest version of Rails.
What happens when you install a gem
When you run gem install
without specifying a version, such as gem install rails
, it will try to install the latest version of the gem. Then it starts by trying to install all the dependencies of the main gem you want to install, based on the versions specified by the gem. If a dependency has a minimum required Ruby version, then that gets checked as well.
If you specify a version, such as gem install actionmailer -v 4.0.13
, then it goes through the same flow as above, except that it uses the rules defined by the version you specified.
The next section explains this more clearly with a specific example.
How gem versioning works
Let’s say we want to install version 4.0.13 of actionmailer using a version of Ruby older than 2.3. If you look it up on rubygems.org, you’ll see that it depends on two gems: actionpack
and mail
. In addition, it allows specific versions of those gems:
actionpack = 4.0.13
mail >= 2.5.4, ~> 2.5
In the case of actionpack, the =
sign means that the only version of actionpack that actionmailer 4.0.13 supports is 4.0.13, so that’s the version of actionpack that will be installed.
For mail, >=
means the version has to be at least 2.5.4, and ~>
is known as the pessimistic operator in Ruby. It means any version after the last period is allowed. In this case, it means all 2.x versions are allowed, but not 3.x or anything else higher than 2.
So, when you install actionmailer 4.0.13 using gem install actionmailer -v 4.0.13
, it might first fetch version 4.0.13 of actionpack, and then it will fetch the latest allowable versions of all of actionpack’s dependencies.
The first one is activesupport
, which is locked to version 4.0.13, and then if you look at activesupport
4.0.13, its first dependency is i18n >= 0.6.9, ~> 0.6
, which means it will fetch the latest 0.x version, which is “0.9.5”.
In turn, that version of i18n
depends on concurrent-ruby ~> 1.0
, and the latest 1.x version of concurrent-ruby
requires Ruby >= 2.3.0. So, with Ruby versions older than 2.3.0, you might get an error that “concurrent-ruby requires Ruby version >= 2.3”.
Where it gets confusing is that the rules that are used to figure out the right combination of gem versions that will work together depends on the Ruby version and the Rubygems version. Newer Rubygems versions are smart enough to also check which version is compatible with the current Ruby version, and should be able to install actionmailer 4.0.13 without any issues. However, these newer Rubygems versions are only available in Ruby 2.3 and higher.
As a Ruby on Mac customer, whenever you install any Ruby version, it will always come with the latest possible Rubygems version, so for Ruby versions 2.3 and higher, you won’t waste time dealing with these types of issues.
With older Ruby and Rubygems versions, the version compatibility will only be determined by the allowable versions, and in some cases, it might start going through the mail
dependencies first. In that case, it will allow the latest 2.x version of mail
, which is 2.8.1. Then it will try to install the latest allowable versions of all the gems that mail 2.8.1 depends on. One of them is net-smtp
, and the mail
gem allows all versions of net-smtp
(“>= 0”).
Then if you click on net-smtp
on rubygems.org, you will see that it depends on net-protocol >= 0
, which means the latest version will be fetched, and that version (0.2.2) depends on Ruby >= 2.6.0, which explains the error “net-protocol requires Ruby version >= 2.6.0”.
Depending on which version of Ruby and Rubygems you’re using, the error might be “timeout requires Ruby version >= 2.6.0” (because net-protocol depends on timeout >= 0, and the latest version requires Ruby >= 2.6.0).
You might still be confused and wonder why would a Rails or actionmailer version that was released in 2015 depend on a gem that didn’t exist until 2020?
It all goes back to how versioning works, so I’ll repeat it:
When version 4.0.13 of actionmailer was released in 2015, it did not require net-protocol because none of actionmailer’s dependencies required net-protocol at the time. In 2015, the latest version of the mail
gem was 2.5.4, and it did not depend on net-smtp
, and none of its dependencies required net-protocol
. This makes sense since net-protocol didn’t even exist back then.
However, version 4.0.13 of actionmailer wasn’t thinking about what would happen in the future, and they were permissive with the versioning of their dependencies. Specifically, they allowed all 2.x versions of the mail gem greater than or equal to 2.5.4, as I mentioned earlier:
mail >= 2.5.4, ~> 2.5
The consequence is that when you install actionmailer today — in a world where net-protocol
exists — directly with gem install actionmailer -v 4.0.13
while using an outdated Ruby version, and if none of its dependencies are installed yet, it will fetch the latest possible version of each of its dependencies, which means it will try to install version 2.8.1 of the mail gem, and then the latest allowable version of the mail gem’s dependencies. net-smtp
is one of those dependencies, and the mail gem uses the most permissive versioning possible (>= 0), which means it will try to install version 0.5.0 of net-smtp
, which in turn allows any version of net-protocol
, and the latest version (0.2.2) requires Ruby >= 2.6.0
Since we can’t modify the versioning scheme of gems that were released in the past, how do we fix this?
How to install the right combination of gems
Using the example from the previous section, in order to install actionmailer
4.0.13 with a Ruby version older than 2.6.0, we need to know which specific versions of the mail
gem are compatible with both actionmailer
4.0.13 and our current Ruby version. For a Rails app, it’s much more complicated because there are a whole lot more combinations of gems we need to figure out.
The standard and expected way to do that in Ruby, and also by far the easiest way, is with Bundler. Each Ruby project that uses gems is expected to have a file (at the root of the project) called Gemfile
that specifies the project’s dependencies. If you’re trying to get an existing Rails 4.x app up and running locally on your computer, it definitely has a Gemfile
. The first few lines of the Gemfile
might look something like this:
source "https://rubygems.org"
ruby "2.3.8"
gem "rails", "~> 4.0.13"
In order to install a Ruby project’s dependencies with Bundler, first you need to install the required Ruby version. Then you also need to install the appropriate version of Bundler, because Ruby didn’t start including the bundler
gem by default until Ruby 2.6.10. Once Bundler is installed, you can install the dependencies in any Ruby project with bundle install
.
As an aside, Ruby on Mac Ultimate automatically installs the correct version of Bundler for you, even for older Ruby versions that don’t normally include it by default.
The very first time you run bundle install
in a project that doesn’t already have a Gemfile.lock
file, Bundler will automatically figure out the right combination of gem versions to use, and it will store that combination in a file called Gemfile.lock
. For example, if you create a Gemfile
like the one below:
source "https://rubygems.org"
ruby "2.3.8"
gem "actionmailer", "= 4.0.13"
and then run bundle install
, Bundler will install mail
version 2.7.1, which is the latest version that works with both Ruby 2.3.8 and actionmailer 4.0.13.
When a project already has a Gemfile.lock
, Bundler will attempt to install all the gems using the specific versions in the Gemfile.lock
. This file acts as a snapshot in time of the right combination of gem versions that worked together. So, if the last time your Rails 4.0.x app was updated, it used a Ruby version older than 2.6, and if your app still worked, then your Gemfile.lock
will most certainly have a version older than 2.8 of the mail
gem, and you will not run into the net-protocol
issue.
Without Bundler, you would have to manually figure out the right combination of gem versions, and install them in the right order. In the actionmailer
example mentioned above, you would have to go through rubygems.org to figure out the right version of the mail
gem that works with your Ruby version, and then you would need to install it first before being able to install actionmailer
. You would have to repeat this process for all the gems required by your project. It would be a nightmare!
Installing gems with gem install vs bundle install
When you install a gem with gem install
, it installs the gem globally in your current Ruby version, and only that Ruby version. For example, if you install Ruby 3.4.5, and then run gem install rails
, it will install the latest version of Rails inside Ruby 3.4.5. If you then install Ruby 3.3.9, Rails won’t be there automatically. You have to install it again.
This makes sense because different versions of gems support different versions of Ruby. Similarly, within the same Ruby version, you might have multiple different projects, each with their own dependencies, and different required versions of the same gems. The way you can make sure each project is using the specific versions of gems it needs is with Bundler.
This is also why it’s important to prefix commands with bundle exec
, and/or run Rails commands with bin/rails
. This ensures you’re using the versions of gems that are specified in your project, which could be different from the versions you installed globally with gem install
or when working on another project.
For example, if you install Rails globally within Ruby 3.4.5 with gem install rails
, it will install the latest version of Rails, which is 8.0.2 as of today. And then if you cd
into a Rails app that also uses Ruby 3.4.5, but with Rails 6.1.7.8 already installed, and you run rails -v
to check the version, it will return 8.0.2, which is not what you want.
But if you run bundle exec rails -v
, it will return 6.1.7.8 as expected. To help you type less characters, Rails apps let you type bin/rails
, which behind the scenes uses Bundler to activate the right version of Rails.
Things to watch out for when using outdated Ruby versions on macOS
If you’re not a Ruby on Mac customer, a common issue you might run into with Ruby versions less than 2.6.0 is when you try to run bundle install
, you might get an error like this:
Your Ruby version is 2.6.10, but your Gemfile specified 2.1.9
“2.1.9” is just an example here. You will run into this issue with any version of Ruby older than 2.6. As mentioned earlier, that’s because Ruby versions older than 2.6 don’t come with Bundler preinstalled.
Ruby on Mac automatically installs the right version of Bundler for you, but if you’re not using Ruby on Mac, the bundle
command won’t exist by default in Ruby < 2.6. However, the computer will see if it exists elsewhere in locations specified in the PATH
, and it will find it in /usr/bin/bundle
, which is the Bundler that came with the system Ruby (the Ruby version preinstalled by Apple), and that version is 2.6.10 in the most recent macOS versions.
Read my guide about the PATH
environment variable to learn more about it and how it affects your dev setup.
stdgems.org is a great site that shows you the default gems for all Ruby versions. You can also see which version of a particular gem was installed in different Ruby versions. For example:
Once people run into that issue about the mismatch between the version in the Gemfile
and the current active Ruby version, assuming they know what the issue is, they try to install Bundler inside Ruby 2.1.9 with gem install bundler
, and they get this error:
ERROR: Error installing bundler:
bundler requires Ruby version >= 2.6.0.
As we learned earlier, running gem install bundler
without specifying a version will try to fetch the very latest version of Bundler, which requires Ruby >= 2.6.0. So, the solution is to install an older version of Bundler that works with Ruby 2.1.9. But first, you need to figure out which version of Bundler works with your desired Ruby version.
With Ruby on Mac, you don’t have to worry about it this. But if you’re not using Ruby on Mac, you can find the right version by following the manual process below:
-
Go the Bundler page on rubygems.org
-
Keep clicking each version until you see a compatible Ruby version under “REQUIRED RUBY VERSION” in the sidebar on the right.
-
Once you find a compatible version of Bundler for your Ruby version, you also need to look at the REQUIRED_RUBYGEMS_VERSION, and see if your desired Ruby version supports the Rubygems versions required by the Bundler version that you need.
-
Now you can install the right version of Bundler like this:
gem install bundler:1.16.6
And then you should be able to run bundle install
in your Rails app.
When working with old projects, remember that your end goal is to get the project running. In some cases, that means updating the Ruby version and/or some gems. This is especially true on newer macOS versions, and on Apple Silicon Macs that are not compatible with older gem versions.
I see a lot of people get stuck because they think they absolutely have to use the Ruby version that was last used, and they waste so much time trying to get things to work. At a minimum, the Ruby version should be updated to the latest patch version (the 3rd digit) of any given Ruby version.
For example, if a project is configured to use Ruby 2.7.0, you will have a hard time installing it on an Apple Silicon Mac. However, the latest 2.7.x version, which is 2.7.8, works fine. This is a very important concept to understand, and I have a whole step-by-step guide that explains how and why to upgrade the Ruby version in your project.
Here are more related articles from my personal site that might be helpful:
The Beginner’s Guide to Bundler and Gemfiles
How to Update Gems in Your Gemfile
Understanding The Gemfile.lock File
What Happens When You Don’t Specify a Version in Your Gemfile
Why You Should Never Use sudo to Install Ruby Gems
Why You Shouldn’t Use the System Ruby to Install Gems on a Mac
I hope this has been helpful!