fluent/fluentd · error · Fluent::ConfigError
Invalid regexp '# ': #
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.
Solutions
- Ensure the combined regex compiles: test with ruby -e "Regexp.new(ARGV.join, Regexp::MULTILINE)" using the stripped bodies.
- Include at least one named capture group like (?<message>.*) across the formatN set.
- Validate the whole config with fluentd --dry-run before deploying.
- 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
- Always include at least one (?<name>...) group in the formatN set.
- Test each regex in an interactive Ruby shell with Regexp::MULTILINE.
- Dry-run the config after touching format lines.
- Escape for both config parsing and Ruby regex (double backslashes where needed).
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
- Invalid regexp in # : #
- format should be Regexp, need //, in #
- Invalid formatN found. N should be 1 - #
- Jump of format index found. format#
- both of utc and localtime are specified, use only one of…
AI-assisted analysis of fluent/fluentd@dd45c6e18d (2026-08-21).
Data as JSON: /api/errors/dca4328a9535af86.
Report an issue: GitHub.
Appendix: 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 })
endView on GitHub (pinned to dd45c6e18d)