rlucas.net: The Next Generation Rotating Header Image

April 29th, 2010:

RubyGems assorted errors, mutating APIs, and fixes

If you’re trying to use a newer (e.g. 1.3.6) version of the ruby “gem” system to install ruby packages (like rails, rake, etc.) on a legacy system with an older (v. 1.9.0) ruby installed, you might find yourself running into problems like this:

$ gem install rake

ERROR: While executing gem ... (ArgumentError)
illegal access mode rb:ascii-8bit

If you run with debugging flags, you might get a slightly more informative stack trace:

$ gem --debug install rake
Exception `NameError' at /usr/local/lib/site_ruby/1.9/rubygems/command_manager.rb:163 - uninitialized constant
Gem::Commands::InstallCommand
Exception `Gem::LoadError' at /usr/local/lib/site_ruby/1.9/rubygems.rb:778 - Could not find RubyGem test-unit (>= 0)

Exception `Gem::LoadError' at /usr/local/lib/site_ruby/1.9/rubygems.rb:778 - Could not find RubyGem sources (>
0.0.1)

Exception `ArgumentError' at /usr/local/lib/site_ruby/1.9/rubygems/format.rb:50 - illegal access mode rb:ascii-8bit
ERROR: While executing gem ... (ArgumentError)
illegal access mode rb:ascii-8bit
/usr/local/lib/site_ruby/1.9/rubygems/format.rb:50:in `initialize'
/usr/local/lib/site_ruby/1.9/rubygems/format.rb:50:in `Gem::Format#from_file_by_path'
/usr/local/lib/site_ruby/1.9/rubygems/installer.rb:118:in `initialize'
/usr/local/lib/site_ruby/1.9/rubygems/dependency_installer.rb:257:in `Gem::DependencyInstaller#install'
/usr/local/lib/site_ruby/1.9/rubygems/dependency_installer.rb:240:in `Gem::DependencyInstaller#install'
/usr/local/lib/site_ruby/1.9/rubygems/commands/install_command.rb:119:in `execute'
/usr/local/lib/site_ruby/1.9/rubygems/commands/install_command.rb:116:in `execute'
/usr/local/lib/site_ruby/1.9/rubygems/command.rb:258:in `Gem::Command#invoke'
/usr/local/lib/site_ruby/1.9/rubygems/command_manager.rb:134:in `process_args'
/usr/local/lib/site_ruby/1.9/rubygems/command_manager.rb:104:in `Gem::CommandManager#run'
/usr/local/lib/site_ruby/1.9/rubygems/gem_runner.rb:58:in `Gem::GemRunner#run'
/usr/bin/gem:21

Ignore the first couple exceptions and focus on the ArgumentError right before the stack trace. What you’re seeing there is a use of a syntax for defining the binary read encoding mode for reading in a file, but it’s a syntax that didn’t make it into ruby core until ~ version 1.9.1.

However, the relevant part of rubygems/format.rb that checks for RUBY_VERSION to determine what syntax to use simply checks for RUBY_VERSION > ‘1.9’.

If you patch that to check for RUBY_VERSION > ‘1.9.0’ you’ll make some progress, but you’ll get stuck again with a similar error:

/usr/local/lib/site_ruby/1.9/rubygems/source_index.rb:91:in `IO#read': can't convert Hash into Integer (TypeError)

Although this one looks quite different, it’s the same effect at play: rubygems/source_index.rb checks for RUBY_VERSION < '1.9', when it really ought to check for RUBY_VERSION < '1.9.1' when it uses a 1.9.1+ specific API (specifying the encoding in IO#read). I've added bugs at RubyForge: [#28154] Gem.binary_mode version test for Ruby 1.9 sets invalid rb:ascii-8bit mode and [#28155] source_index.rb uses 1.9.1 IO#read API under RUBY_VERSION 1.9.0; other 1.9.0 issues Hot-patching may be required if you find yourself needing to get gem 1.3.6 working under Ruby 1.9.0. (For example, this is the Ruby 1.9 that comes packaged with Debian 4.0.) If so, it should be safe to make the changes I've indicated above. I'm hesitating to provide a patch file as I am not certain that I've got this 100% right; YMMV. Thank goodness for open source. That said, WTF is a core API item like IO#read doing changing between point versions, without it being loudly obvious in the docs??