ruby/ruby · error · Gem::Exception

Unable to download '#{spec.full_name}'

Error message

Unable to download '#{spec.full_name}'

What it means

Gem::Source::SpecificFile#download returns the wrapped file's path only when the passed spec == @spec, and Gem::Specification#== compares class plus name, version, and platform. The error means the spec handed to download describes a different gem (or a different version/platform) than the .gem file this source wraps — most often a dependency's spec routed to the wrong source.

Source

Thrown at lib/rubygems/source/specific_file.rb:41

  end

  ##
  # The Gem::Specification extracted from this .gem.

  attr_reader :spec

  def load_specs(*a) # :nodoc:
    [@name]
  end

  def fetch_spec(name) # :nodoc:
    return @spec if name == @name
    raise Gem::Exception, "Unable to find '#{name}'"
  end

  def download(spec, dir = nil) # :nodoc:
    return @path if spec == @spec
    raise Gem::Exception, "Unable to download '#{spec.full_name}'"
  end

  def pretty_print(q) # :nodoc:
    q.object_group(self) do
      q.group 2, "[SpecificFile:", "]" do
        q.breakable
        q.text @path
      end
    end
  end

  ##
  # Orders this source against +other+.
  #
  # If +other+ is a SpecificFile from a different gem name +nil+ is returned.
  #
  # If +other+ is a SpecificFile from the same gem name the versions are
  # compared using Gem::Version#<=>

View on GitHub (pinned to 0e5b888e1c)

Solutions

  1. Call download with the source's own spec: src.download(src.spec)
  2. Guard before calling: skip the source unless spec == src.spec, and route other specs to sources that actually hold them
  3. For plain installs, use gem install ./foo-1.0.gem and let RubyGems pick dependencies from proper sources

Example fix

# before
specific = Gem::Source::SpecificFile.new("foo-1.0.gem")
specific.download(resolved_bar_spec)  #=> Unable to download 'bar-2.0'

# after
cached = sources.find {|s| s.is_a?(Gem::Source::SpecificFile) && s.spec == spec }
path = cached ? cached.download(spec) : remote_source.download(spec)
Defensive patterns

Strategy: type-guard

Type guard

# Gem::Specification#== compares name, version, platform (specification.rb)
def specific_file_holds?(source, spec)
  spec.is_a?(Gem::Specification) && spec == source.spec
end
path = specific_file_holds?(src, spec) ? src.download(spec) : nil

Prevention

When it happens

Trigger: source.download(spec) where spec was resolved elsewhere (a dependency's spec) rather than the spec parsed from the wrapped .gem; version/platform differences between the requested spec and the file's spec.

Common situations: Custom installers/resolvers iterating sources and calling download with each candidate spec; platform mixups (requesting the ruby platform spec for a x86_64-linux .gem); version skew after rebuilding a gem without updating the caller.

Related errors


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