Bug #22015
openSuccess without RUBY_BOX=1, Failure with RUBY_BOX=1
Description
$ ruby -v
ruby 4.1.0dev (2026-04-24T13:35:04Z master 52ee497f36) +PRISM [arm64-darwin25]
$ ruby -e 'require "bundler/inline"; gemfile {}'
It ran fine as expected, but it failed when I added RUBY_BOX=1.
$ RUBY_BOX=1 ruby -e 'require "bundler/inline"; gemfile {}'
ruby: warning: Ruby::Box is experimental, and the behavior may change in the future!
See https://docs.ruby-lang.org/en/master/Ruby/Box.html for known issues, etc.
/Users/niku/.local/share/mise/installs/ruby/4.1-dev/lib/ruby/4.1.0+1/rubygems/specification.rb:2064:in 'Gem::Specification#method_missing': undefined method 'expanded_dependencies' for an instance of Gem::Specification (NoMethodError)
from /Users/niku/.local/share/mise/installs/ruby/4.1-dev/lib/ruby/4.1.0+1/bundler/resolver/spec_group.rb:42:in 'Array#each'
from /Users/niku/.local/share/mise/installs/ruby/4.1-dev/lib/ruby/4.1.0+1/bundler/resolver/spec_group.rb:42:in 'Enumerable#flat_map'
from /Users/niku/.local/share/mise/installs/ruby/4.1-dev/lib/ruby/4.1.0+1/bundler/resolver/spec_group.rb:42:in 'Bundler::Resolver::SpecGroup#dependencies'
from /Users/niku/.local/share/mise/installs/ruby/4.1-dev/lib/ruby/4.1.0+1/bundler/resolver/spec_group.rb:67:in 'Bundler::Resolver::SpecGroup#equivalent?'
from /Users/niku/.local/share/mise/installs/ruby/4.1-dev/lib/ruby/4.1.0+1/bundler/resolver/spec_group.rb:51:in 'Bundler::Resolver::SpecGroup#merge'
from /Users/niku/.local/share/mise/installs/ruby/4.1-dev/lib/ruby/4.1.0+1/bundler/resolver.rb:279:in 'block (2 levels) in Bundler::Resolver#all_versions_for'
from /Users/niku/.local/share/mise/installs/ruby/4.1-dev/lib/ruby/4.1.0+1/bundler/resolver.rb:278:in 'Array#each'
from /Users/niku/.local/share/mise/installs/ruby/4.1-dev/lib/ruby/4.1.0+1/bundler/resolver.rb:278:in 'block in Bundler::Resolver#all_versions_for'
from /Users/niku/.local/share/mise/installs/ruby/4.1-dev/lib/ruby/4.1.0+1/bundler/resolver.rb:258:in 'Hash#each'
from /Users/niku/.local/share/mise/installs/ruby/4.1-dev/lib/ruby/4.1.0+1/bundler/resolver.rb:258:in 'Enumerable#reduce'
from /Users/niku/.local/share/mise/installs/ruby/4.1-dev/lib/ruby/4.1.0+1/bundler/resolver.rb:258:in 'Bundler::Resolver#all_versions_for'
from /Users/niku/.local/share/mise/installs/ruby/4.1-dev/lib/ruby/4.1.0+1/bundler/resolver.rb:54:in 'block in Bundler::Resolver#setup_solver'
from /Users/niku/.local/share/mise/installs/ruby/4.1-dev/lib/ruby/4.1.0+1/bundler/resolver.rb:378:in 'Bundler::Resolver#filtered_versions_for'
from /Users/niku/.local/share/mise/installs/ruby/4.1-dev/lib/ruby/4.1.0+1/bundler/resolver.rb:58:in 'block in Bundler::Resolver#setup_solver'
from /Users/niku/.local/share/mise/installs/ruby/4.1-dev/lib/ruby/4.1.0+1/bundler/resolver.rb:169:in 'Bundler::Resolver#versions_for'
from /Users/niku/.local/share/mise/installs/ruby/4.1-dev/lib/ruby/4.1.0+1/bundler/resolver.rb:449:in 'block in Bundler::Resolver#prepare_dependencies'
from /Users/niku/.local/share/mise/installs/ruby/4.1-dev/lib/ruby/4.1.0+1/bundler/resolver.rb:443:in 'Hash#each'
from /Users/niku/.local/share/mise/installs/ruby/4.1-dev/lib/ruby/4.1.0+1/bundler/resolver.rb:443:in 'Enumerable#filter_map'
from /Users/niku/.local/share/mise/installs/ruby/4.1-dev/lib/ruby/4.1.0+1/bundler/resolver.rb:443:in 'Bundler::Resolver#prepare_dependencies'
from /Users/niku/.local/share/mise/installs/ruby/4.1-dev/lib/ruby/4.1.0+1/bundler/resolver.rb:63:in 'Bundler::Resolver#setup_solver'
from /Users/niku/.local/share/mise/installs/ruby/4.1-dev/lib/ruby/4.1.0+1/bundler/resolver.rb:28:in 'Bundler::Resolver#start'
from /Users/niku/.local/share/mise/installs/ruby/4.1-dev/lib/ruby/4.1.0+1/bundler/definition.rb:750:in 'Bundler::Definition#start_resolution'
from /Users/niku/.local/share/mise/installs/ruby/4.1-dev/lib/ruby/4.1.0+1/bundler/definition.rb:351:in 'Bundler::Definition#resolve'
from /Users/niku/.local/share/mise/installs/ruby/4.1-dev/lib/ruby/4.1.0+1/bundler/definition.rb:253:in 'Bundler::Definition#missing_specs'
from /Users/niku/.local/share/mise/installs/ruby/4.1-dev/lib/ruby/4.1.0+1/bundler/definition.rb:257:in 'Bundler::Definition#missing_specs?'
from /Users/niku/.local/share/mise/installs/ruby/4.1-dev/lib/ruby/4.1.0+1/bundler/inline.rb:64:in 'block in Object#gemfile'
from /Users/niku/.local/share/mise/installs/ruby/4.1-dev/lib/ruby/4.1.0+1/bundler/settings.rb:146:in 'Bundler::Settings#temporary'
from /Users/niku/.local/share/mise/installs/ruby/4.1-dev/lib/ruby/4.1.0+1/bundler/inline.rb:60:in 'Object#gemfile'
from -e:1:in '<main>'
Updated by jneen (Jeanine Adkisson) 21 days ago
ยท Edited
I believe this to be related to Symbol#to_proc, as changing bundler/resolver/spec_group.rb:41 from:
def dependencies
@dependencies ||= @specs.flat_map(&:expanded_dependencies).uniq.sort
end
to
def dependencies
@dependencies ||= @specs.flat_map { |s| s.expanded_dependencies }.uniq.sort
end
removes the error.
The method is on the module Bundler::MatchMetadata, which is included into ::Gem::Specification with a re-opening in bundler/rubygems_ext.rb. What's strange is I verified that these all load in the user box, and that the object_id of ::Gem::Specification (including @specs[0].class) are all identical.
Updated by niku (niku _) 13 days ago
I found a minimal reproduction case.
The issue seems to relate to how Enumerable#flat_map handles Symbol#to_proc within a Ruby::Box environment. Notably, map(&:method) works as expected, while flat_map(&:method) fails.
$ ruby -v
ruby 4.1.0dev (2026-05-01T19:25:51Z master f2845eab29) +PRISM [arm64-darwin25]
$ RUBY_BOX=1 ruby -e "
box = Ruby::Box.new
box.eval(<<~'RUBY')
class Array
def box_only_method
:ok
end
end
# Works as expected
p [[1]].flat_map { |ary| ary.box_only_method } # => [:ok]
p [[1]].map(&:box_only_method) # => [:ok]
# Fails with NoMethodError
p [[1]].flat_map(&:box_only_method)
RUBY
"
[:ok]
[:ok]
eval:12:in 'Array#each': undefined method 'box_only_method' for an instance of Array (NoMethodError)
from eval:12:in 'Enumerable#flat_map'
Updated by niku (niku _) 8 days ago
I believe https://github.com/ruby/ruby/pull/16865 addresses this issue.
Updated by mame (Yusuke Endoh) 3 days ago
- Status changed from Open to Assigned
- Assignee set to tagomoris (Satoshi Tagomori)