ruby/ruby · error · Gem::Exception

ruby_code case not handled: #{obj.class}

Error message

ruby_code case not handled: #{obj.class}

What it means

ruby_code (used by Gem::Specification#to_ruby and gem specification --ruby) renders each attribute value as Ruby source through a case over known classes: String/Array/Hash, Gem::Version, DateLike, Time, Numeric, true/false/nil, Gem::Platform, Gem::Requirement. Any other class on a specification attribute falls through and raises — the serializer simply has no branch for that type.

Source

Thrown at lib/rubygems/specification.rb:2267

  # object.

  def ruby_code(obj)
    case obj
    when String             then obj.dump + ".freeze"
    when Array              then "[" + obj.map {|x| ruby_code x }.join(", ") + "]"
    when Hash               then
      seg = obj.keys.sort.map {|k| "#{k.to_s.dump} => #{obj[k].to_s.dump}" }
      "{ #{seg.join(", ")} }"
    when Gem::Version       then ruby_code(obj.to_s)
    when DateLike           then obj.strftime("%Y-%m-%d").dump
    when Time               then obj.strftime("%Y-%m-%d").dump
    when Numeric            then obj.inspect
    when true, false, nil   then obj.inspect
    when Gem::Platform      then "Gem::Platform.new(#{ruby_code obj.to_a})"
    when Gem::Requirement   then
      list = obj.as_list
      "Gem::Requirement.new(#{ruby_code(list.size == 1 ? obj.to_s : list)})"
    else raise Gem::Exception, "ruby_code case not handled: #{obj.class}"
    end
  end

  private :ruby_code

  ##
  # List of dependencies that will automatically be activated at runtime.

  def runtime_dependencies
    dependencies.select(&:runtime?)
  end

  ##
  # True if this gem has the same attributes as +other+.

  def same_attributes?(spec)
    @@attributes.all? {|name, _default| send(name) == spec.send(name) }
  end

View on GitHub (pinned to 0e5b888e1c)

Solutions

  1. Upgrade RubyGems — serialization branches for additional classes have been added over releases
  2. Find and normalize the offending field: walk spec's instance variables and convert anything that is not a supported type (String, Array, Hash, Gem::Version, Date/Time, Numeric, Gem::Platform, Gem::Requirement) before calling to_ruby
  3. Stop assigning custom objects to Gem::Specification attributes; store extras in metadata as plain strings

Example fix

# before
spec.metadata_pointing_at_custom = MyCustomValue.new(x)
puts spec.to_ruby  #=> ruby_code case not handled: MyCustomValue

# after
spec.metadata["custom"] = "plain string"  # keep attribute values serializable
puts spec.to_ruby
Defensive patterns

Strategy: type-guard

Type guard

SUPPORTED = [String, Array, Hash, Gem::Version, Date, Time, Numeric, TrueClass, FalseClass, NilClass, Gem::Platform, Gem::Requirement]
def to_ruby_safe?(spec)
  spec.instance_variables.all? do |iv|
    v = spec.instance_variable_get(iv)
    v.nil? || SUPPORTED.any? {|k| v.is_a?(k) }
  end
end

Prevention

When it happens

Trigger: spec.to_ruby / gem spec pkg/x-1.0.gem --ruby when a specification field holds an object outside the handled set — e.g. a custom class or subclass assigned to an attribute, odd objects introduced by YAML/Marshal round-trips, or types supported only by newer RubyGems versions.

Common situations: Regenerating a gemspec from an installed/built gem after third-party code mutated spec fields; very old marshalled specs with legacy attribute types; automation that assigns convenience objects to spec attributes.

Related errors


AI-assisted analysis of ruby/ruby@0e5b888e1c (2026-08-21). Data as JSON: /api/errors/dd65f4faa06f571f. Report an issue: GitHub.