fluent/fluentd · critical · Fluent::UnrecoverableError
Invalid path component detected in #{matched}: #{replace}
Error message
Invalid path component detected in #{matched}: #{replace} What it means
Fluentd raises this Fluent::UnrecoverableError inside Output#extract_placeholders when a buffer path placeholder (e.g. ${key} or ${tag}) is replaced by a chunk-key value containing a path-escape component. The guard tests the substituted value against INVALID_PATH_COMPONENT_PATTERN (%r{\.\.[/\\]|^[/\\]}, lib/fluent/plugin/output.rb:48), i.e. '../', '..\\', or a leading '/'/'\\'. UnrecoverableError means the chunk can never be flushed and is eventually discarded, so the events in it are lost. The check exists to stop record/tag contents from writing outside the configured buffer directory.
Source
Thrown at lib/fluent/plugin/output.rb:877
else
log.warn "${chunk_id} is not allowed in this plugin. Pass Chunk instead of metadata in extract_placeholders's 2nd argument"
end
}
# Then, replace other ${chunk_key}s.
if !@chunk_keys.empty? && metadata.variables
hash = {'${tag}' => '${tag}'} # not to erase this wrongly
@chunk_keys.each do |key|
hash["${#{key}}"] = metadata.variables[key.to_sym]
end
rvalue = rvalue.gsub(CHUNK_KEY_PLACEHOLDER_PATTERN) do |matched|
replace = hash.fetch(matched) do
log.warn "chunk key placeholder '#{matched[2..-2]}' not replaced. template:#{str}"
''
end
if replace.to_s.match?(INVALID_PATH_COMPONENT_PATTERN)
raise Fluent::UnrecoverableError, "Invalid path component detected in #{matched}: #{replace}"
end
replace
end
# Check if the number of parent directory components (../) has increased due to variable substitution
if rvalue.match?(PARENT_DIRECTORY_PATTERN)
if rvalue.scan(PARENT_DIRECTORY_PATTERN).size > str.scan(PARENT_DIRECTORY_PATTERN).size
raise Fluent::UnrecoverableError, "Invalid path component detected, replaced to: #{rvalue}"
end
end
end
if rvalue =~ CHUNK_KEY_PLACEHOLDER_PATTERN
log.warn "chunk key placeholder '#{$1}' not replaced. template:#{str}"
end
rvalue
endView on GitHub (pinned to dd45c6e18d)
Solutions
- Sanitize the chunk-key value before buffering: add a record_transformer/filter that strips '../', '..\\' and leading '/' (e.g. app ${record['app'].to_s.gsub(%r{\.\.[/\\]}, '_').sub(%r{^[/\\]}, '')}).
- Stop using raw record values in path templates: use ${chunk_id} or a digest/hash of the value as the directory name.
- Route records with malformed chunk-key values to a separate label/dead-letter output so only bad events are dropped.
- If nested directories under the buffer path are genuinely required, pre-map values to a fixed safe directory list instead of interpolating raw values.
Example fix
# before
<match logs.**>
@type file
path /var/log/fluent/${app}
<buffer app>
@type file
</buffer>
</match>
# after: sanitize the chunk key before it becomes a path component
<filter logs.**>
@type record_transformer
enable_ruby true
<record>
app ${record['app'].to_s.gsub(%r{\.\.[/\\]}, '_').sub(%r{^[/\\]}, '')}
</record>
</filter> Defensive patterns
Strategy: validation
Validate before calling
# before events reach a buffered output with path placeholders:
INVALID_PATH = %r{\.\.[/\\]|^[/\\]}
if record['app'].to_s.match?(INVALID_PATH)
router.emit_stream('app.invalid', OneEventStream.new([[Fluent::EventTime.now, record]]))
end Type guard
def safe_path_component?(v)
v.is_a?(String) && !v.match?(%r{\.\.[/\\]|^[/\\]})
end Try / catch
rescue Fluent::UnrecoverableError => e log.error 'buffer chunk dropped: invalid path component', error: e # record to dead-letter; chunk is unrecoverable by design, do not retry
Prevention
- Never interpolate raw record values into buffer path; prefer ${chunk_id} or a digest of the value.
- Add a sanitize filter (record_transformer with gsub) ahead of any path-based output.
- Run fluentd --dry-run after every config change.
- Monitor num_errors and buffer retry counters to catch discarded chunks early.
When it happens
Trigger: A buffered output configured with <buffer app> and path /var/log/fluent/${app}, where a record's 'app' value is '../../etc/x', 'a/../..', 'C:\\evil', or '/abs/path'; likewise ${tag} when the input tag starts with '/' or contains '../'. Extraction happens at buffer-chunk creation, so the error surfaces on write/flush attempts.
Common situations: Using unvalidated request paths, container names, hostnames, or log file names as chunk keys in file/s3 outputs; forwarding untrusted events whose fields feed path templates; upgrading to newer fluentd where this traversal guard (INVALID_PATH_COMPONENT_PATTERN) was introduced and previously-tolerated values now fail.
Related errors
- Invalid path component detected, replaced to: #{rvalue}
- <buffer> section is configured, but plugin '#{self.class}' d
- secondary plugin '#{self.class}' must support buffering, but
- tag must be a String: #{tag.class}
- this plugin '#{self.class}' cannot handle arguments for <buf
AI-assisted analysis of fluent/fluentd@dd45c6e18d (2026-08-21).
Data as JSON: /api/errors/4d27654502488e5b.
Report an issue: GitHub.