ruby/ruby · error · RuntimeError
Cannot set ractor local storage for non-current ractor
Error message
Cannot set ractor local storage for non-current ractor
What it means
Obsolete instance-level Ractor#[]= writes ractor-local storage and carries the same restriction as []: only the current ractor may touch its own storage. other_ractor[:key] = value raises RuntimeError 'Cannot set ractor local storage for non-current ractor' before the primitive runs. Use the class form Ractor[:key] = value, or set storage inside the owning ractor's own code.
Source
Thrown at ractor.rb:487
rb_ractor_make_shareable(obj);
}
end
end
# Gets a value from ractor-local storage for the current Ractor.
# Obsolete, use Ractor.[] instead.
def [](sym)
if (self != Ractor.current)
raise RuntimeError, "Cannot get ractor local storage for non-current ractor"
end
Primitive.ractor_local_value(sym)
end
# Sets a value in ractor-local storage for the current Ractor.
# Obsolete, use Ractor.[]= instead.
def []=(sym, val)
if (self != Ractor.current)
raise RuntimeError, "Cannot set ractor local storage for non-current ractor"
end
Primitive.ractor_local_value_set(sym, val)
end
# Gets a value from ractor-local storage for the current Ractor.
def self.[](sym)
Primitive.ractor_local_value(sym)
end
# Sets a value in ractor-local storage for the current Ractor.
def self.[]=(sym, val)
Primitive.ractor_local_value_set(sym, val)
end
# call-seq:
# Ractor.store_if_absent(key){ init_block }
#
# If the corresponding ractor-local value is not set, yields a value withView on GitHub (pinned to 0e5b888e1c)
Solutions
- Set storage inside the ractor that owns it: Ractor.new { Ractor[:cfg] = load_cfg; ... }
- Pass initial data as Ractor.new(args) block parameters instead of storage writes from outside
- Use the class form Ractor[:key] = value for the current ractor's storage
Example fix
# before
r = Ractor.new { work }
r[:mode] = :fast # RuntimeError: Cannot set ractor local storage for non-current ractor
# after
Ractor[:mode] = :fast # sets MAIN ractor's storage
r = Ractor.new(:fast) { |mode| work(mode) } # child gets data via arguments Defensive patterns
Strategy: validation
Validate before calling
# set storage only on the current ractor
r[sym] = val if r == Ractor.current
# to initialize a child's storage, set it inside the child's own block:
Ractor.new { Ractor[:mode] = :fast; work } Type guard
def own_ractor?(r) r == Ractor.current end
Try / catch
begin
r[sym] = val
rescue RuntimeError => e
raise unless e.message.include?('ractor local storage')
Ractor[sym] = val # write the calling ractor's storage instead
end Prevention
- Seed ractors via constructor arguments or messages, never via storage writes from outside
- Use the class form Ractor[:key] = value everywhere for current-ractor storage
- Treat the obsolete instance []/[]= as removed during upgrades
When it happens
Trigger: Parent code trying to 'seed' a spawned ractor via child_ractor[:init] = data before/after spawn; generic obj[key] = assignment helpers that receive a Ractor; Thread#[]= muscle memory applied to Ractor instances.
Common situations: Seeding configuration into workers; code ported from Ruby 3.0 Ractor previews; job frameworks treating ractors as hash-configurable targets.
Related errors
- Cannot get ractor local storage for non-current ractor
- must be called with a block
- specify at least one Ractor::Port or Ractor
- should be Ractor::Port or Ractor
- end of file reached
AI-assisted analysis of ruby/ruby@0e5b888e1c (2026-08-21).
Data as JSON: /api/errors/29d0d5f187c17adb.
Report an issue: GitHub.