fluent/fluentd · error · ArgumentError

Template for parser must be a Class, callable object or regu

Error message

Template for parser must be a Class, callable object or regular expression object

What it means

Raised as ArgumentError by the legacy v0.12 registration helper Fluent::Compat::TextParser.register_template(type, template, time_format=nil). Accepted shapes are: a parser Class, any object responding to #call, or a Regexp (wrapped into a RegexpParser together with the optional time_format). Anything else - a parser instance, a String, a Hash of options - is rejected.

Source

Thrown at lib/fluent/compat/parser.rb:91

      def parse(text, &block)
        if block
          @parser.parse(text, &block)
        else
          @parser.parse(text) { |time, record|
            return time, record
          }
        end
      end

      def self.register_template(type, template, time_format=nil)
        # TODO: warn when deprecated to use Plugin.register_parser directly
        if template.is_a?(Class) || template.respond_to?(:call)
          Fluent::Plugin.register_parser(type, template)
        elsif template.is_a?(Regexp)
          Fluent::Plugin.register_parser(type, Proc.new { RegexpParser.new(template, {'time_format' => time_format}) })
        else
          raise ArgumentError, "Template for parser must be a Class, callable object or regular expression object"
        end
      end

      def self.lookup(format)
        # TODO: warn when deprecated to use Plugin.new_parser or RegexpParser.new directly
        if format.nil?
          raise ConfigError, "'format' parameter is required"
        end

        if format[0] == ?/ && format[format.length-1] == ?/
          # regexp
          begin
            regexp = Regexp.new(format[1..-2])
            if regexp.named_captures.empty?
              raise "No named captures"
            end
          rescue
            raise ConfigError, "Invalid regexp '#{format[1..-2]}': #{$!}"

View on GitHub (pinned to dd45c6e18d)

Solutions

  1. Pass the parser class, a Proc, or a Regexp: register_template('apache', /.../, '%d/%b/%Y:%H:%M:%S %z')
  2. For factory-style registration pass a callable that returns parser instances
  3. Migrate to the v1 API: Fluent::Plugin.register_parser('my_parser', MyParser)

Example fix

# before
Fluent::Compat::TextParser.register_template('my_parser', MyParser.new)

# after
Fluent::Compat::TextParser.register_template('my_parser', MyParser)
Fluent::Compat::TextParser.register_template('apache', /\A(?<host>[^ ]*) [^ ]* (?<user>[^ ]*) \[(?<time>[^\]]*)\]/, '%d/%b/%Y:%H:%M:%S %z')
Defensive patterns

Strategy: type-guard

Validate before calling

raise ArgumentError, 'template must be a Class, callable, or Regexp' unless template.is_a?(Class) || template.is_a?(Regexp) || template.respond_to?(:call)
Fluent::Compat::TextParser.register_template(type, template, time_format)

Type guard

def parser_template?(t)
  t.is_a?(Class) || t.is_a?(Regexp) || t.respond_to?(:call)
end

Try / catch

begin
  Fluent::Compat::TextParser.register_template(type, template)
rescue ArgumentError => e
  raise unless e.message.include?('must be a Class, callable object or regular expression')
  Fluent::Compat::TextParser.register_template(type, template.class)
end

Prevention

When it happens

Trigger: TextParser.register_template('my_parser', MyParser.new) (instance instead of class); passing an options Hash or format String; an object that lacks #call.

Common situations: Porting v0.12 plugin registration code; copy-pasting registration calls between parsers of different API generations; switching from Regexp-based to class-based parsers mid-migration.

Related errors


AI-assisted analysis of fluent/fluentd@dd45c6e18d (2026-08-21). Data as JSON: /api/errors/b9b87f7da266ff18. Report an issue: GitHub.