Project

General

Profile

Bug #22267

Updated by nobu (Nobuyoshi Nakada) about 1 month ago

On ruby-head, the Active Support (Rails) test suite fails with two Ractor-related errors (rails-nightly build 4651, https://buildkite.com/rails/rails-nightly/builds/4651#01a016ac-eada-492d-9548-44089079b973/L8324). 

 Rails CI failure. To reproduce on the Rails side, build ruby master, then in a rails/rails checkout run the two tests from activesupport/: 

 ``` 
 $ ruby -v 
 ruby 4.1.0dev (2026-08-26T07:05:32Z master 346b261abe) +PRISM [x86_64-linux] 

 $ bundle exec ruby -Ilib:test test/time_zone_test.rb -n test_formatted_offset_in_ractor 
 #<Thread:...> terminated with exception (report_on_exception is true): 
 lib/active_support/time_with_zone.rb:78:in 'ActiveSupport::TimeWithZone#period': undefined method 'period_for_utc' for nil (NoMethodError) 
         from lib/active_support/time_with_zone.rb:139:in 'ActiveSupport::TimeWithZone#zone' 
         from lib/active_support/time_with_zone.rb:59:in 'ActiveSupport::TimeWithZone#initialize' 
         from lib/active_support/time_with_zone.rb:535:in 'ActiveSupport::TimeWithZone#marshal_load' 

   1) Error: 
 TimeZoneTest#test_formatted_offset_in_ractor: 
 Ractor::RemoteError: thrown by remote Ractor. 
     lib/active_support/testing/ractors_assertions.rb:15:in 'Ractor#join' 
     lib/active_support/testing/ractors_assertions.rb:15:in 'ActiveSupport::Testing::RactorsAssertions#on_ractor' 
     test/time_zone_test.rb:895:in 'TimeZoneTest#test_formatted_offset_in_ractor' 

 $ bundle exec ruby -Ilib:test test/notifications_test.rb -n test_record_and_set_subscriptions_when_using_a_regexp 
   1) Error: 
 Notifications::NotificationSubscriptionTest#test_record_and_set_subscriptions_when_using_a_regexp: 
 Ractor::Error: can not copy Hash object. 
     lib/active_support/ractors.rb:117:in 'Ractor.make_shareable' 
     lib/active_support/ractors.rb:117:in 'ActiveSupport::Ractors.make_shareable' 
     lib/active_support/ractors.rb:79:in 'ActiveSupport::Ractors.try_make_shareable' 
     lib/active_support/notifications.rb:359:in 'ActiveSupport::Notifications.record_subscriptions' 
     lib/active_support/notifications.rb:314:in 'ActiveSupport::Notifications.subscribe' 
     test/notifications_test.rb:604:in 'block in <class:NotificationSubscriptionTest>' 
 ``` 
 git bisect points at [GH-18194] #18194 (Per-Ractor GC). Both reduce to Ractor copy and reproduce without Rails. 

 Steps to reproduce (pure Ruby). 

 (1) mirrors `TimeZoneTest#test_formatted_offset_in_ractor` TimeZoneTest#test_formatted_offset_in_ractor — an object with a Time ivar (which now forces a Marshal fallback) whose marshal_load reconstructs from state only reachable in the main Ractor: 

 ```ruby ``` 
 class Registry 
   @zones = { "z" => Object.new } 
   def self.find(name) = @zones.fetch(name)     # reads a class-level ivar 
 end 
 class Wrapper 
   def initialize(name) = (@name = name; @time = Time.now; @zone = Registry.find(name)) 
   def marshal_dump = @name 
   def marshal_load(name) = (@name = name; @time = Time.now; @zone = Registry.find(name)) 
 end 
 port = Ractor::Port.new 
 Ractor.new(port, Wrapper.new("z")) { |p, o| p.send :ok }.join 
 p port.receive 
 ``` 

 (2) mirrors Notifications...`test_record_and_set_subscriptions_when_using_a_regexp` Notifications...test_record_and_set_subscriptions_when_using_a_regexp — a Hash holding a Set and a shareable Proc: 

 ```ruby ``` 
 require "set" 
 Ractor.make_shareable({ s: Set.new([1, 2]), p: Ractor.shareable_proc {} }, copy: true) 
 ``` 
 Expected behavior. On Ruby 4.0.6 and before [GH-18194] #18194 (50745e3e48): 

 - (1) copies natively, `marshal_load` marshal_load is not called, and prints :ok. 
 - (2) succeeds. 

 Actual behavior. On current master (346b261abe) and since [GH-18194] #18194 (4f6c34eea6): 

 (1): 

 ``` 
 #<Thread:...> terminated with exception (report_on_exception is true): 
 -:3:in 'Registry.find': can not get unshareable values from instance variables of classes/modules from non-main Ractors (@zones from Registry) (Ractor::IsolationError) 
       from -:8:in 'Wrapper#marshal_load' 
 -:11:in 'Ractor#join': thrown by remote Ractor. (Ractor::RemoteError) 
       from -:11:in '<main>' 
 ``` 

 marshal_load now runs in the receiver Ractor, where the object cannot reach main-Ractor state. In Active Support the same happens in `TimeWithZone#marshal_load`; TimeWithZone#marshal_load; there `Time.find_zone` Time.find_zone rescues this and returns nil, so the Rails trace shows `period_for_utc` period_for_utc for nil instead. 

 (2): 

 ``` 
 -:2:in 'Ractor.make_shareable': can not copy Hash object. (Ractor::Error) 
       from -:2:in '<main>' 
 -:2:in 'Ractor.make_shareable': no _dump_data is defined for class Proc (TypeError) 
       from -:2:in '<main>' 
 ``` 

 [GH-18194]: https://github.com/ruby/ruby/pull/18194

Back