{"record":{"id":"3e2403ba0dd89c03","repo":"heartcombo/simple_form","slug":"simpleform-include-component-expects-a-module-but","errorCode":null,"errorMessage":"SimpleForm.include_component expects a module but got: #{component.class}","messagePattern":"SimpleForm\\.include_component expects a module but got: #(.+?)","errorType":"exception","errorClass":"TypeError","httpStatus":null,"severity":"error","filePath":"lib/simple_form.rb","lineNumber":335,"sourceCode":"  #      # Create a wrapper using the custom component.\n  #      config.wrappers :input_group, tag: :div, error_class: :error do |b|\n  #        b.use :label\n  #        b.optional :prepend\n  #        b.use :input\n  #        b.use :append\n  #      end\n  #    end\n  #\n  #    # Using the custom component in the form.\n  #    <%= simple_form_for @blog, wrapper: input_group do |f| %>\n  #      <%= f.input :title, prepend: true %>\n  #    <% end %>\n  #\n  def self.include_component(component)\n    if Module === component\n      SimpleForm::Inputs::Base.include(component)\n    else\n      raise TypeError, \"SimpleForm.include_component expects a module but got: #{component.class}\"\n    end\n  end\nend\n\nrequire 'simple_form/railtie' if defined?(Rails)\n","sourceCodeStart":317,"sourceCodeEnd":341,"githubUrl":"https://github.com/heartcombo/simple_form/blob/18f38aad0bdeca2ba1815043b94d96fdbbe6a325/lib/simple_form.rb#L317-L341","documentation":"SimpleForm.include_component includes a user-supplied module into SimpleForm::Inputs::Base so its methods can be referenced by name inside wrapper definitions (b.use :my_component). The guard 'Module === component' requires an actual Module; passing a Class, a String, nil, or any other object raises TypeError (lib/simple_form.rb:335). Classes are rejected on purpose: components are mixins, not input classes.","triggerScenarios":"Calling SimpleForm.include_component(CustomComponent) where CustomComponent was declared with 'class' instead of 'module'; passing a constant built via Struct.new or Class.new; passing a symbol/string constant name; the argument being nil because the module file was not yet loaded when the initializer ran.","commonSituations":"Copy-pasting a custom component example but writing 'class CustomComponent'; defining the component as a Struct/Class.new metaprogrammed object; referencing an autoloaded (Zeitwerk) constant inside an initializer, which runs before autoload, so the value is nil or raises on the wrong object.","solutions":["Rewrite the component as a module (module PrefixComponent; def prefix(wrapper_options); ...; end; end) and pass the module constant to include_component","If the component was produced by Class.new/Struct.new, extract its instance methods into a plain module first","Make sure the module is loaded before the call: require it explicitly at the top of config/initializers/simple_form.rb or place it in lib and require it, since initializers run before Rails autoloading"],"exampleFix":"# before\nclass PrefixComponent\n  def prefix\n    # ...\n  end\nend\nSimpleForm.include_component PrefixComponent  # TypeError: got Class\n\n# after\nmodule PrefixComponent\n  def prefix(wrapper_options)\n    template.content_tag(:span, options[:prefix], class: 'input-group-text')\n  end\nend\nSimpleForm.include_component PrefixComponent","handlingStrategy":"type-guard","validationCode":"raise TypeError, \"component must be a Module, got #{component.class}\" unless component.is_a?(Module)\nSimpleForm.include_component(component)","typeGuard":"def component_module?(obj)\n  obj.is_a?(Module) && !obj.nil?\nend\n# a Class instance is never is_a?(Module) in Ruby, so classes fail this check by design\ncomponent_module?(PrefixComponent) # => true","tryCatchPattern":"begin\n  SimpleForm.include_component(component)\nrescue TypeError => e\n  Rails.logger.error(\"skipping component registration: #{e.message}\")\nend","preventionTips":["Author components as modules only, never classes or Structs","require component files at the top of the initializer — initializers run before Zeitwerk autoloading","Add a shared spec that calls include_component and renders a form using each registered component"],"tags":["simple-form","include-component","type-error","module","custom-component"],"backgroundTag":"expected-module-got-class","analyzedSha":"18f38aad0bdeca2ba1815043b94d96fdbbe6a325","analyzedAt":"2026-08-21T18:23:08.988Z","schemaVersion":2},"datasetVersion":"2026-08-21T23:17:16.201Z"}