ViewComponent/view_component · error · ViewComponent::SlotPredicateNameError

COMPONENT declares a slot named SLOT_NAME, which ends with a

Error message

COMPONENT declares a slot named SLOT_NAME, which ends with a question mark.

This isn't allowed because the ViewComponent framework already provides predicate methods ending in `?`.

To fix this issue, choose a different name.

What it means

Raised when a slot name ends with a question mark (lib/view_component/slotable.rb:337-339). For every registered slot the framework defines a predicate method named <slot>? (for example items? at lib/view_component/slotable.rb:179), so a slot literally carrying a question mark would fight the generated predicate and Ruby method naming. The check runs in both the singular and the plural validators.

Source

Thrown at lib/view_component/slotable.rb:338

        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)
        end
      end
    end

    def __vc_get_slot(slot_name)
      @__vc_set_slots ||= {}

View on GitHub (pinned to 9f22c36fa7)

Solutions

  1. Remove the question mark from the slot name
  2. Rely on the generated presence predicate: after renders_one :available the template calls available?
  3. Sanitize generated names by stripping a trailing question mark before passing them to renders_one or renders_many

Example fix

# before
class BadgeComponent < ViewComponent::Base
  renders_one :verified? # raises SlotPredicateNameError
end

# after
class BadgeComponent < ViewComponent::Base
  renders_one :verified # template: show the badge when verified?
end
Defensive patterns

Strategy: validation

Validate before calling

def slot_name_safe?(name)
  !name.to_s.end_with?("?")
end

slot_name_safe?(:available?) # => false

Try / catch

begin
  renders_one(candidate.to_sym)
rescue ViewComponent::InvalidSlotNameError
  # covers SlotPredicateNameError plus the reserved, call_-prefixed and uncountable subclasses
  candidate = candidate.to_s.chomp("?")
  retry
end

Prevention

When it happens

Trigger: renders_one :available?, renders_many :active?, or any string or symbol passed to either macro whose to_s form ends with a question mark, including names generated from CMS field keys or I18n keys that contain one.

Common situations: Copying the Ruby predicate idiom into slot names for boolean-ish optional areas; generated slot names from data that include question marks; renaming a helper method such as confirmed? into a slot during a component refactor.

Related errors


AI-assisted analysis of ViewComponent/view_component@9f22c36fa7 (2026-08-23). Data as JSON: /api/errors/049b3fc392b9e8ca. Report an issue: GitHub.