ViewComponent/view_component · error · ViewComponent::MultipleInlineTemplatesError

Inline templates can only be defined once per-component.

Error message

Inline templates can only be defined once per-component.

What it means

ViewComponent lets a component define its template inline in Ruby by calling a class-level method ending in _template (erb_template, haml_template, slim_template), intercepted by method_missing in ViewComponent::InlineTemplate. A component renders exactly one template, so a second *_template call on the same class raises ViewComponent::MultipleInlineTemplatesError as soon as the class body is evaluated (at boot or on first autoload). The guard is the per-class @__vc_inline_template_defined flag, so a subclass may define its own inline template but the same class body may not.

Source

Thrown at lib/view_component/inline_template.rb:14

# frozen_string_literal: true

module ViewComponent # :nodoc:
  module InlineTemplate
    extend ActiveSupport::Concern

    Template = Struct.new(:source, :language, :path, :lineno)

    class_methods do
      def method_missing(method, *args)
        return super if !method.end_with?("_template")

        if defined?(@__vc_inline_template_defined) && @__vc_inline_template_defined
          raise MultipleInlineTemplatesError
        end

        if args.size != 1
          raise ArgumentError, "wrong number of arguments (given #{args.size}, expected 1)"
        end

        ext = method.to_s.gsub("_template", "")
        template = args.first

        @__vc_inline_template_language = ext

        caller = caller_locations(1..1)[0]
        @__vc_inline_template = Template.new(
          template,
          ext,
          caller.absolute_path || caller.path,
          caller.lineno
        )

View on GitHub (pinned to 9f22c36fa7)

Solutions

  1. Delete one of the *_template calls so the class defines exactly one inline template (check for erb_template, haml_template, slim_template, etc. in the file).
  2. If you were switching template languages, merge the markup into a single call in the new language and remove the old one.
  3. If you intended two variants, split them into two components (or a base class plus a subclass, since subclasses may define their own inline template).
  4. If both formats must coexist for one component, move them to template files (app/components/<name>/*.erb plus variant-aware templates) instead of inline templates.

Example fix

# before
class CardComponent < ViewComponent::Base
  erb_template <<-ERB
    <div class="card"><%= content %></div>
  ERB

  haml_template "%div.card= content" # second inline template -> MultipleInlineTemplatesError
end

# after
class CardComponent < ViewComponent::Base
  erb_template <<-ERB
    <div class="card"><%= content %></div>
  ERB
end
Defensive patterns

Strategy: validation

Validate before calling

# Before adding an inline template programmatically
class CardComponent < ViewComponent::Base; end

raise "already has an inline template" unless CardComponent.__vc_inline_template.nil?
CardComponent.erb_template <<-ERB
  <div><%= content %></div>
ERB

Try / catch

begin
  # component class body with *_template call
rescue ViewComponent::MultipleInlineTemplatesError
  Rails.logger.error("#{name} defines two inline templates; keeping one")
  raise
end

Prevention

When it happens

Trigger: Calling two *_template class methods in one component class body, e.g. erb_template followed by haml_template; pasting a new template DSL call without deleting the old one; a copy-pasted component that keeps both the original erb_template and an added slim_template.

Common situations: Migrating a component from ERB to Haml/Slim and leaving both calls behind; merging two inline-template components into one; onboarding confusion where devs assume each format needs its own declaration. Because the raise happens during class load, the failure often surfaces first in boot logs or the first request that autoloads the file.

Related errors


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