fluent/fluentd · error · Fluent::ConfigError

Invalid regexp '#{formats}': #{e}

Error message

Invalid regexp '#{formats}': #{e}

What it means

MultilineParser#configure (lib/fluent/plugin/parser_multiline.rb:67) joins the format1..formatN regexes and compiles the combined expression; any failure is re-raised as Fluent::ConfigError with the joined source. Two distinct causes land here: the regex body is syntactically invalid (RegexpError from Regexp.new), or the manual 'No named captures' raise fires because the combined regexp has zero named capture groups. Both abort configuration.

Source

Thrown at lib/fluent/plugin/parser_multiline.rb:67

          yield(time, record)
          m
        end
      end

      def configure(conf)
        super

        formats = parse_formats(conf).compact.map { |f| f[1..-2] }.join
        begin
          regexp = Regexp.new(formats, Regexp::MULTILINE)
          if regexp.named_captures.empty?
            raise "No named captures"
          end
          regexp_conf = Fluent::Config::Element.new("", "", { "expression" => "/#{formats}/m" }, [])
          @parser = Fluent::Plugin::MultilineParser::MultilineRegexpParser.new
          @parser.configure(conf + regexp_conf)
        rescue => e
          raise Fluent::ConfigError, "Invalid regexp '#{formats}': #{e}"
        end

        if @format_firstline
          check_format_regexp(@format_firstline, 'format_firstline')
          @firstline_regex = Regexp.new(@format_firstline[1..-2])
        end
      end

      def parse(text, &block)
        loop do
          m =
            if @unmatched_lines
              @parser.call(text) do |time, record|
                if time && record
                  yield(time, record)
                else
                  yield(Fluent::EventTime.now, { 'unmatched_line' => text })
                end

View on GitHub (pinned to dd45c6e18d)

Solutions

  1. Ensure the combined regex compiles: test with ruby -e "Regexp.new(ARGV.join, Regexp::MULTILINE)" using the stripped bodies.
  2. Include at least one named capture group like (?<message>.*) across the formatN set.
  3. Validate the whole config with fluentd --dry-run before deploying.
  4. Check Ruby (not PCRE/grep) regex syntax: named groups use (?<name>...), and backslashes must survive config parsing.

Example fix

# before
format1 /^\d{4}/   # no named capture -> 'No named captures'
format2 /\s+.*/
# after
format1 /(?<time>^\d{4}-\d{2}-\d{2})/
format2 /(?<message>\s+.*)/
Defensive patterns

Strategy: validation

Validate before calling

# pre-deploy: verify combined multiline regex compiles and has named captures
bodies = %w[format1_body format2_body] # paste stripped bodies here
joined = bodies.join
Regexp.new(joined, Regexp::MULTILINE)
abort 'no named captures' if Regexp.new(joined, Regexp::MULTILINE).named_captures.empty?

Prevention

When it happens

Trigger: format1 /(?<log>\w+)/ format2 /(?<tail>\s+.*)/ with an unbalanced paren or stray '*' in one of them; multi-line Java stack-trace formats where every formatN uses numbered captures () instead of named (?<x>...); format strings containing raw '/' that breaks the /.../ delimiters after [1..-2] stripping.

Common situations: Configuring in_tail multiline parsing for Java/MySQL log formats; converting old fluentd v0 'format_firstline /.../' recipes to the format1..format20 scheme; escaping errors when porting regexes from other tools (double-escaping \d in config files).

Related errors


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