ViewComponent/view_component · error · ViewComponent::RedefinedSlotError
COMPONENT declares the SLOT_NAME slot multiple times. To fi
Error message
COMPONENT declares the SLOT_NAME slot multiple times. To fix this issue, choose a different slot name.
What it means
Raised by __vc_raise_if_slot_registered when the name is already present in registered_slots (lib/view_component/slotable.rb:331-335). Slots are declared once: the first registration generates the getter, predicate and setter methods, and a second registration is refused rather than redefined. Subclasses clone registered_slots through inherited (lib/view_component/slotable.rb:198-201), so redeclaring a parent slot in a child also raises.
Source
Thrown at lib/view_component/slotable.rb:333
end
def __vc_validate_singular_slot_name(slot_name)
if slot_name.to_sym == :content
raise ContentSlotNameError.new(name)
end
if RESERVED_NAMES[:singular].include?(slot_name.to_sym)
raise ReservedSingularSlotNameError.new(name, slot_name)
end
__vc_raise_if_slot_conflicts_with_call(slot_name)
__vc_raise_if_slot_ends_with_question_mark(slot_name)
__vc_raise_if_slot_registered(slot_name)
end
def __vc_raise_if_slot_registered(slot_name)
if registered_slots.key?(slot_name)
raise RedefinedSlotError.new(name, slot_name)
end
end
def __vc_raise_if_slot_ends_with_question_mark(slot_name)
raise SlotPredicateNameError.new(name, slot_name) if slot_name.to_s.end_with?("?")
end
def __vc_raise_if_slot_conflicts_with_call(slot_name)
if slot_name.start_with?("call_")
raise InvalidSlotNameError, "Slot cannot start with 'call_'. Please rename #{slot_name}"
end
end
def __vc_raise_if_slot_name_uncountable(slot_name)
slot_name = slot_name.to_s
if slot_name.pluralize == slot_name.singularize
raise UncountableSlotNameError.new(name, slot_name)
endView on GitHub (pinned to 9f22c36fa7)
Solutions
- Delete the duplicate declaration; the first one already works
- In a subclass, remove the redeclaration: inherited slots are cloned and keep working without new code
- If the subclass needs a genuinely different slot, choose a new name instead of the parent slot name
- When switching a slot between renders_one and renders_many, replace the old declaration in the same edit rather than keeping both
Example fix
# before class ListComponent < ViewComponent::Base renders_one :item, ItemComponent renders_many :items, ItemComponent # raises RedefinedSlotError on :item end # after class ListComponent < ViewComponent::Base renders_many :items, ItemComponent # one concept, one name family end
Defensive patterns
Strategy: validation
Validate before calling
def slot_name_family_free?(klass, name) candidates = [name.to_sym, name.to_s.singularize.to_sym, name.to_s.pluralize.to_sym].uniq (candidates & klass.registered_slots.keys).empty? end slot_name_family_free?(ListComponent, :items) # => false once :items or :item is registered
Try / catch
# treat config-driven registration as idempotent begin register_slot_from_config(name) rescue ViewComponent::RedefinedSlotError # the slot already exists; skip instead of failing the whole component load end
Prevention
- Declare each concept once: choose the singular or the plural form, never both
- Never redeclare inherited slots in subclasses; rely on the cloned registration
- Search the component and its ancestors for a name before adding a new slot
- Assert the expected set of registered_slots keys in a spec when slots come from configuration
When it happens
Trigger: The same declaration twice in one class, for example renders_one :header followed by renders_one :header; mixing kinds on one name family, because renders_one validates the pluralized name at :81 and renders_many validates the singularized name at :151, so renders_one :item next to renders_many :items raises either way; and redeclaring any slot inherited from a parent component.
Common situations: Copy-pasted slot blocks; refactoring between renders_one and renders_many while keeping the same name; subclasses that try to override or re-register an inherited slot; code generators that append declarations without checking existing ones.
Related errors
- A method called 'SETTER_METHOD_NAME' already exists and woul
- COMPONENT declares a slot named SLOT_NAME, which is a reserv
- COMPONENT declares a slot named content, which is a reserved
- COMPONENT declares a slot named SLOT_NAME, which ends with a
- Slot cannot start with 'call_'. Please rename #{slot_name}
AI-assisted analysis of ViewComponent/view_component@9f22c36fa7 (2026-08-23).
Data as JSON: /api/errors/7488a7901ae49a81.
Report an issue: GitHub.