Bug #22267
openActive Support tests started failing on ruby master (bisected to [GH-18194])
Description
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 (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 — an object with a Time ivar (which now forces a Marshal fallback) whose marshal_load reconstructs from state only reachable in the main Ractor:
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 — a Hash holding a Set and a shareable Proc:
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 (50745e3e48):
- (1) copies natively,
marshal_loadis not called, and prints :ok. - (2) succeeds.
Actual behavior. On current master (346b261abe) and since GH-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; there Time.find_zone rescues this and returns nil, so the Rails trace shows period_for_utc for nil instead.
(2):