ViewComponent/view_component · error · ViewComponent::Serializable::UnserializableError
Cannot serialize anonymous component class #{component_class
Error message
Cannot serialize anonymous component class #{component_class.inspect} What it means
Proxy#initialize requires a named component class because serialization stores component_class.name and deserialization resolves it back via safe_constantize. An anonymous class (Class.new(ViewComponent::Base) never assigned to a constant, so name is nil) has no stable name, so Proxy.new — reached via Component.render_later — raises ViewComponent::Serializable::UnserializableError ('Cannot serialize anonymous component class'). The check is component_class.name.nil?.
Source
Thrown at lib/view_component/serializable/proxy.rb:32
raise ArgumentError, "Cannot deserialize unknown component: #{hash["component_class"]}" unless klass
args = ActiveJob::Arguments.deserialize(hash["initialize_args"] || [])
proxy = new(klass, *args)
Array(hash["slot_calls"]).each do |call|
method_name = call["method"].to_sym
slot_args = ActiveJob::Arguments.deserialize(call["args"])
proxy.public_send(method_name, *slot_args)
end
proxy
end
attr_reader :component_class, :initialize_args, :slot_calls
def initialize(component_class, *args)
if component_class.name.nil?
raise UnserializableError, "Cannot serialize anonymous component class #{component_class.inspect}"
end
@component_class = component_class
@initialize_args = args
@slot_calls = []
end
ruby2_keywords :initialize
# Implements the Rails renderable interface
def render_in(view_context, &block)
if block
raise UnserializableError, "Cannot serialize render_in with a block"
end
build_component.render_in(view_context)
end
def method_missing(method_name, *args, &block)
if slot_method?(method_name)View on GitHub (pinned to 9f22c36fa7)
Solutions
- Assign the class to a constant so .name returns a resolvable string: define it with `class DynamicCardComponent < ViewComponent::Base` in a file, or use const_set on the intended namespace.
- If generating classes at runtime, register each one under a stable, unique constant name before calling render_later.
- If the component must stay anonymous, render it synchronously (build the instance and call render_in) instead of using render_later.
Example fix
# before card = Class.new(ViewComponent::Base) do erb_template "<div><%= content %></div>" end proxy = card.render_later # UnserializableError: anonymous class # after class DynamicCardComponent < ViewComponent::Base erb_template "<div><%= content %></div>" end proxy = DynamicCardComponent.render_later
Defensive patterns
Strategy: validation
Validate before calling
component_class = Class.new(ViewComponent::Base) { erb_template "<div>" }
raise ArgumentError, "component must be named to defer-render" if component_class.name.nil?
component_class.render_later Prevention
- Only call render_later on classes assigned to constants (defined with `class Foo < ViewComponent::Base`).
- For dynamically built classes, const_set them under a stable namespace before deferring.
- In test factories, reuse named fixture components instead of Class.new.
When it happens
Trigger: Class.new(ViewComponent::Base) { erb_template ... }.render_later; dynamically built components kept in local variables and never assigned to a constant; test factories creating component classes programmatically and then passing them to render_later.
Common situations: DSL/builder patterns that generate component classes at runtime; specs that define throwaway components with Class.new; helper methods that return newly defined classes.
Related errors
- Inline templates can only be defined once per-component.
- wrong number of arguments (given #{args.size}, expected 1)
- Cannot serialize render_later with a block
- Cannot deserialize unknown component: #{hash["component_clas
- Cannot serialize render_in with a block
AI-assisted analysis of ViewComponent/view_component@9f22c36fa7 (2026-08-23).
Data as JSON: /api/errors/f99ceb7f223d1889.
Report an issue: GitHub.