ruby/ruby · error · ArgumentError
Attempting to visit unknown element #{e.inspect}
Error message
Attempting to visit unknown element #{e.inspect} What it means
The SafeMarshal base visitor dispatches each parsed element through a table (DISPATCH) built from every constant under Gem::SafeMarshal::Elements; the table's default routes any unrecognized element class to visit_unknown_element, which raises ArgumentError. Reaching it means the element object being visited is not one of the known element types — normally an internal version skew between the reader that produced the elements and the visitor consuming them, or a foreign/monkey-patched element class.
Source
Thrown at lib/rubygems/safe_marshal/visitors/visitor.rb:21
module Gem::SafeMarshal::Visitors
class Visitor
def visit(target)
send DISPATCH.fetch(target.class), target
end
private
DISPATCH = Gem::SafeMarshal::Elements.constants.each_with_object({}) do |c, h|
next if c == :Element
klass = Gem::SafeMarshal::Elements.const_get(c)
h[klass] = :"visit_#{klass.name.gsub("::", "_")}"
h.default = :visit_unknown_element
end.compare_by_identity.freeze
private_constant :DISPATCH
def visit_unknown_element(e)
raise ArgumentError, "Attempting to visit unknown element #{e.inspect}"
end
def visit_Gem_SafeMarshal_Elements_Array(target)
target.elements.each {|e| visit(e) }
end
def visit_Gem_SafeMarshal_Elements_Bignum(target); end
def visit_Gem_SafeMarshal_Elements_False(target); end
def visit_Gem_SafeMarshal_Elements_Float(target); end
def visit_Gem_SafeMarshal_Elements_Hash(target)
target.pairs.each do |k, v|
visit(k)
visit(v)
end
end
def visit_Gem_SafeMarshal_Elements_HashWithDefaultValue(target)View on GitHub (pinned to 0e5b888e1c)
Solutions
- Align versions: update rubygems and bundler together (`gem update --system`, `bundle update --bundler`) so the reader and visitor come from the same release
- Remove or update any gem/plugin that monkey-patches Gem::SafeMarshal internals
- If you call the visitor directly, only pass elements produced by Gem::SafeMarshal::Reader from the same rubygems version
- Rescue ArgumentError around the safe_load call and treat the payload as unparseable (refetch or reject)
Example fix
# before def render(elements) visitor.visit(elements) end # after begin visitor.visit(elements) rescue ArgumentError => e raise if e.message !~ /unknown element/ # reader/visitor mismatch: regenerate elements with the current reader end
Defensive patterns
Strategy: try-catch
Type guard
known_element = ->(e) { Gem::SafeMarshal::Elements.constants.any? { |c| Gem::SafeMarshal::Elements.const_get(c) === e } } Try / catch
begin
visitor.visit(element)
rescue ArgumentError => e
raise unless e.message.include?('unknown element')
# reader/visitor version skew: regenerate or reject payload
end Prevention
- Update rubygems and bundler together so reader and visitor ship from one release
- Do not monkey-patch Gem::SafeMarshal reader/element internals
- Only feed the visitor elements produced by the matching reader version
When it happens
Trigger: Feeding the visitor element objects not defined in Gem::SafeMarshal::Elements: mixing a newer reader (which emits new element types) with an older visitor from another rubygems/bundler version, calling Gem::SafeMarshal::Visitors::ToRuby#visit directly on a hand-built element tree, or a gem monkey-patching the reader to introduce custom element classes.
Common situations: Vendored or pinned old rubygems/Bundler running next to newer installed components; internal API misuse by a tool that constructs element objects itself; rare corrupted streams that decode into unexpected structure.
Related errors
- Unable to call #{method.inspect} on #{receiver.inspect}, per
- 17
- Specs #{name} from #{remote} is expected to be an Array but
- Failed to find gems #{options[:args]} #{options[:version]}
- Your Ruby version is #{RUBY_VERSION}, but your #{gem_deps_fi
AI-assisted analysis of ruby/ruby@0e5b888e1c (2026-08-21).
Data as JSON: /api/errors/9d8bf396f4e70202.
Report an issue: GitHub.