How to fix REXML::ParseException TypeError in Cocoapods
Updated on
If you just installed the latest version of Cocoapods, and you’re getting an error related to REXML::ParseException
after running pod install
, then
I’ll not only show you how to fix it, but also explain why you’re getting this error. That way, you’ll feel more confident troubleshooting similar Ruby issues in the future.
Here’s an example error message you might see:
REXML::ParseException - #<TypeError: wrong argument type String (expected Regexp)>
/Library/Ruby/Gems/2.6.0/gems/rexml-3.2.9/lib/rexml/source.rb:220:in `scan'
/Library/Ruby/Gems/2.6.0/gems/rexml-3.2.9/lib/rexml/source.rb:220:in `match'
/Library/Ruby/Gems/2.6.0/gems/rexml-3.2.9/lib/rexml/parsers/baseparser.rb:227:in `pull_event'
/Library/Ruby/Gems/2.6.0/gems/rexml-3.2.9/lib/rexml/parsers/baseparser.rb:207:in `pull'
/Library/Ruby/Gems/2.6.0/gems/rexml-3.2.9/lib/rexml/parsers/treeparser.rb:23:in `parse'
/Library/Ruby/Gems/2.6.0/gems/rexml-3.2.9/lib/rexml/document.rb:448:in `build'
/Library/Ruby/Gems/2.6.0/gems/rexml-3.2.9/lib/rexml/document.rb:101:in `initialize'
/Library/Ruby/Gems/2.6.0/gems/xcodeproj-1.24.0/lib/xcodeproj/workspace.rb:50:in `new'
/Library/Ruby/Gems/2.6.0/gems/xcodeproj-1.24.0/lib/xcodeproj/workspace.rb:50:in `initialize'
/Library/Ruby/Gems/2.6.0/gems/cocoapods-1.15.2/lib/cocoapods/installer/user_project_integrator.rb:111:in `new'
/Library/Ruby/Gems/2.6.0/gems/cocoapods-1.15.2/lib/cocoapods/installer/user_project_integrator.rb:111:in `create_workspace'
/Library/Ruby/Gems/2.6.0/gems/cocoapods-1.15.2/lib/cocoapods/installer/user_project_integrator.rb:71:in `integrate!'
/Library/Ruby/Gems/2.6.0/gems/cocoapods-1.15.2/lib/cocoapods/installer.rb:929:in `block in integrate_user_project'
/Library/Ruby/Gems/2.6.0/gems/cocoapods-1.15.2/lib/cocoapods/user_interface.rb:64:in `section'
/Library/Ruby/Gems/2.6.0/gems/cocoapods-1.15.2/lib/cocoapods/installer.rb:925:in `integrate_user_project'
/Library/Ruby/Gems/2.6.0/gems/cocoapods-1.15.2/lib/cocoapods/installer.rb:185:in `integrate'
/Library/Ruby/Gems/2.6.0/gems/cocoapods-1.15.2/lib/cocoapods/installer.rb:170:in `install!'
/Library/Ruby/Gems/2.6.0/gems/cocoapods-1.15.2/lib/cocoapods/command/install.rb:52:in `run'
/Library/Ruby/Gems/2.6.0/gems/claide-1.1.0/lib/claide/command.rb:334:in `run'
/Library/Ruby/Gems/2.6.0/gems/cocoapods-1.15.2/lib/cocoapods/command.rb:52:in `run'
/Library/Ruby/Gems/2.6.0/gems/cocoapods-1.15.2/bin/pod:55:in `<top (required)>'
This particular error is caused by a bug in the rexml
gem, specifically in version 3.2.9. This has since been fixed in version 3.3.0 that was released on June 11, 2024. Today is June 24 (or later), so how come this error is still happening in Cocoapods?
To answer that question, you need to understand how gems and gem versioning work. This might seem like a long post, but it will be worth your time to understand some basic concepts about Ruby gems. Here’s a table of contents to give you an overview:
- TL;DR
- What are Ruby gems and how are versions defined?
- What happens when you install a gem
- How to install a newer version of Ruby properly on a Mac
- How to use a newer version of Ruby with an existing project
- More examples of troubleshooting gem installation errors
TL;DR
Here are the main points from this article:
-
If you’re on a Mac, never use the system Ruby (the version of Ruby that came preinstalled by Apple).
-
Instead, use a version manager to install a newer and separate version of Ruby that won’t interfere with the system Ruby. Ruby on Mac makes this super easy.
-
Never use
sudo
to install gems.
What are Ruby gems and how are versions defined?
A gem is a way to package Ruby code so that it can be installed on a computer. 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 cocoapods. You can see that the latest version has 17 runtime dependencies, but each of those dependencies might have their own dependencies. So, the total number of gems cocoapods depends on is a lot more than 17.
You’ll also notice that each gem has some symbols and numbers next to it. That defines which versions of the dependencies are allowed. Symbols like >==
and <
should be self-explanatory, but you might not be familiar with ~>
, known as the pessimistic operator in Ruby.
When using the pessimistic operator, it means that any version after the last dot is allowed. For example, addressable ~> 2.8
means any 2.x version above or equal to 2.8 is allowed, but not 3.x or anything higher. And rexml ~> 3.2.4
means any 3.2.x version above or equal to 3.2.4 is allowed, but not 3.3.x or higher.
What happens when you install a gem
When you run gem install
without specifying a version, such as gem install cocoapods
, 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.
Another thing to understand is that when you install a Ruby version, it comes with certain gems. And if a gem already exists in the Ruby version where you are trying to install Cocoapods, and if the version of that gem satisfies the requirements of Cocoapods’ dependencies, then it will just use that version. Otherwise, it will try to install the latest allowable version.
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:
As you can see, Ruby version 2.6.10 (which is the version that comes preinstalled in the most recent macOS versions) installs version 3.1.9.1 of rexml
.
That means that when you install the latest version of Cocoapods while using Ruby 2.6.10, it will try to install the latest 3.2.x version of rexml
, because cocoapods
1.15.2 depends on xcodeproj >= 1.23.0, < 2.0
, and the latest version of xcodeproj
that satisfies that rule is 1.24.0, which in turn depends on rexml ~> 3.2.4
, and the latest possible version of rexml
that satisfies that rule is 3.2.9, which has a bug that causes the REXML::ParseException - #<TypeError: wrong argument type String (expected Regexp)>
error.
Unfortunately for Cocoapods users, the maintainers of rexml
chose to bump the version to 3.3.0 after fixing this bug, as opposed to 3.2.10.
So how do we avoid this bug while using Cocoapods?
There are a few solutions that are possible:
- The
rexml
maintainers could yank version 3.2.9 from rubygems.org - The maintainers of
xcodeproj
could release a new 1.x version that requiresrexml
to be at least 3.3.0 - You can keep using the system Ruby and manually uninstall rexml 3.2.9 and install an older 3.2.x version
- You can install a newer Ruby version that comes with a 3.2.x version of rexml
The last solution is the safest one that you can use right away. Using the system Ruby is a very bad idea, and in order to uninstall and reinstall rexml using the system Ruby, you must use sudo
, which is also highly discouraged.
I’ve been working with Ruby for almost 15 years, and not once have I ever had to use sudo
to install gems. Anyone who tells you to use the system Ruby and/or to use sudo
to install gems is only repeating what they saw online or from ChatGPT, without understanding how Ruby works.
Unfortunately, even the official instructions in the Cocoapods documentation recommend using the system Ruby on a Mac, and to use sudo
to install Cocoapods. I strongly disagree with both of those, because they are the source of the most common issues people face when working with Ruby on a Mac. This REXML::ParseException
is just one of many examples of these frustrating issues.
To learn more, read these articles from my personal site:
Why You Should Never Use sudo to Install Ruby Gems
Why You Shouldn’t Use the System Ruby to Install Gems on a Mac
And I’m not the only one to warn about this. Check out the Don’t Use System Ruby site as well.
How to install a newer version of Ruby properly on a Mac
The only method I recommend for installing Ruby on macOS is to use a version manager to install a newer and separate version of Ruby that will not interfere with the system Ruby. Ruby on Mac makes this super easy. With a single terminal command, you’ll be up and running with Cocoapods in 15 minutes or less. Read how much people love Ruby on Mac.
Alternatively, you can spend about an hour doing it all manually by following my free step-by-step guide for installing Ruby on a Mac, which has helped hundreds of thousands of people over the past 12 years.
The reason why installing a newer Ruby version will fix this specific REXML::ParseException
issue is because all versions of Ruby between 3.0.7 and 3.3.4 install rexml
version 3.2.4 or greater (but less than 3.2.9) by default, which satisfies the Cocoapods requirements.
For example, if you install Ruby 3.3.4, it installs rexml
version 3.2.8. And if you then run gem install cocoapods
while using Ruby 3.3.4, it will see that rexml
3.2.8 already exists, and so it won’t try to install a newer version.
However, if you install Ruby 3.4.6 (the latest as of today), it will install rexml
version 3.4.0, which doesn’t have the bug.
How to use a newer version of Ruby with an existing project
If you’re using Cocoapods inside an existing project that was configured to use an older version of Ruby (such as a React Native app, or any project with a Gemfile
and/or a .ruby-version
file), read my step-by-step guide that explains How and Why to Upgrade the Ruby Version in Your Project.
More examples of troubleshooting gem installation errors
Once you have a proper Ruby development environment, you can solidify your understanding of how gem versioning works by reading these articles that go through other scenarios that result in gem installation failures:
How to install the locomotivecms_wagon gem on a Mac
Error installing rails: net-protocol requires Ruby version >= 2.6.0
I hope this has been helpful!