{"record":{"id":"049b3fc392b9e8ca","repo":"ViewComponent/view_component","slug":"component-declares-a-slot-named-slot-name-which-e","errorCode":null,"errorMessage":"COMPONENT declares a slot named SLOT_NAME, which ends with a question mark.\n\nThis isn't allowed because the ViewComponent framework already provides predicate methods ending in `?`.\n\nTo fix this issue, choose a different name.","messagePattern":"COMPONENT declares a slot named SLOT_NAME, which ends with a question mark\\.\n\nThis isn't allowed because the ViewComponent framework already provides predicate methods ending in `\\?`\\.\n\nTo fix this issue, choose a different name\\.","errorType":"exception","errorClass":"ViewComponent::SlotPredicateNameError","httpStatus":null,"severity":"error","filePath":"lib/view_component/slotable.rb","lineNumber":338,"sourceCode":"        end\n\n        if RESERVED_NAMES[:singular].include?(slot_name.to_sym)\n          raise ReservedSingularSlotNameError.new(name, slot_name)\n        end\n\n        __vc_raise_if_slot_conflicts_with_call(slot_name)\n        __vc_raise_if_slot_ends_with_question_mark(slot_name)\n        __vc_raise_if_slot_registered(slot_name)\n      end\n\n      def __vc_raise_if_slot_registered(slot_name)\n        if registered_slots.key?(slot_name)\n          raise RedefinedSlotError.new(name, slot_name)\n        end\n      end\n\n      def __vc_raise_if_slot_ends_with_question_mark(slot_name)\n        raise SlotPredicateNameError.new(name, slot_name) if slot_name.to_s.end_with?(\"?\")\n      end\n\n      def __vc_raise_if_slot_conflicts_with_call(slot_name)\n        if slot_name.start_with?(\"call_\")\n          raise InvalidSlotNameError, \"Slot cannot start with 'call_'. Please rename #{slot_name}\"\n        end\n      end\n\n      def __vc_raise_if_slot_name_uncountable(slot_name)\n        slot_name = slot_name.to_s\n        if slot_name.pluralize == slot_name.singularize\n          raise UncountableSlotNameError.new(name, slot_name)\n        end\n      end\n    end\n\n    def __vc_get_slot(slot_name)\n      @__vc_set_slots ||= {}","sourceCodeStart":320,"sourceCodeEnd":356,"githubUrl":"https://github.com/ViewComponent/view_component/blob/9f22c36fa7d7b44098a8ed97472e3b4674ae420f/lib/view_component/slotable.rb#L320-L356","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","solutions":["Remove the question mark from the slot name","Rely on the generated presence predicate: after renders_one :available the template calls available?","Sanitize generated names by stripping a trailing question mark before passing them to renders_one or renders_many"],"exampleFix":"# before\nclass BadgeComponent < ViewComponent::Base\n  renders_one :verified? # raises SlotPredicateNameError\nend\n\n# after\nclass BadgeComponent < ViewComponent::Base\n  renders_one :verified # template: show the badge when verified?\nend","handlingStrategy":"validation","validationCode":"def slot_name_safe?(name)\n  !name.to_s.end_with?(\"?\")\nend\n\nslot_name_safe?(:available?) # => false","typeGuard":null,"tryCatchPattern":"begin\n  renders_one(candidate.to_sym)\nrescue ViewComponent::InvalidSlotNameError\n  # covers SlotPredicateNameError plus the reserved, call_-prefixed and uncountable subclasses\n  candidate = candidate.to_s.chomp(\"?\")\n  retry\nend","preventionTips":["Never put a question mark in a slot name; every slot already gets a free predicate method","Strip trailing question marks from generated or CMS-driven names before declaration"],"tags":["ruby","rails","view-component","slots","naming","predicate-methods"],"backgroundTag":"invalid-identifier-name","analyzedSha":"9f22c36fa7d7b44098a8ed97472e3b4674ae420f","analyzedAt":"2026-08-23T10:20:47.008Z","schemaVersion":2},"datasetVersion":"2026-08-23T13:39:53.451Z"}