fluent/fluentd · error · Fluent::ConfigError
secondary plugin '#{self.class}' must support buffering, but
Error message
secondary plugin '#{self.class}' must support buffering, but doesn't What it means
Fluentd raises this ConfigError while configuring a `<secondary>` section when the plugin chosen as secondary does not support buffering. A secondary receives the primary's buffered chunks after retries fail, so it must implement a buffered write path (`#write` or `#try_write`). Plugins that only implement `#process` (synchronous) set `@buffering = false` and are rejected here.
Source
Thrown at lib/fluent/plugin/output.rb:298
else
if @as_secondary
# secondary plugin always works as buffered plugin without buffer instance
@buffering = true
else
# @buffering.nil? shows that enabling buffering or not will be decided in lazy way in #start
@buffering = nil
end
end
else # buffered or delayed_commit is supported by `unless` of first line in this method
@buffering = true
end
end
# Enable to update record size metrics or not
@enable_size_metrics = !!system_config.enable_size_metrics
if @as_secondary
if !@buffering && !@buffering.nil?
raise Fluent::ConfigError, "secondary plugin '#{self.class}' must support buffering, but doesn't"
end
end
if (@buffering || @buffering.nil?) && !@as_secondary
# When @buffering.nil?, @buffer_config was initialized with default value for all parameters.
# If so, this configuration MUST success.
@chunk_keys = @buffer_config.chunk_keys.dup
@chunk_key_time = !!@chunk_keys.delete('time')
@chunk_key_tag = !!@chunk_keys.delete('tag')
if @chunk_keys.any? { |key|
begin
k = Fluent::PluginHelper::RecordAccessor::Accessor.parse_parameter(key)
if k.is_a?(String)
k !~ CHUNK_KEY_PATTERN
else
if key.start_with?('$[')
raise Fluent::ConfigError, "in chunk_keys: bracket notation is not allowed"
elseView on GitHub (pinned to dd45c6e18d)
Solutions
- Use the dedicated `@type secondary_file` plugin, which writes failed chunks to a directory
- Use another buffering-capable output (e.g. `file`, `forward` to a backup host) as the secondary
- Remove the `<secondary>` section if you do not need a fallback for failed chunks
Example fix
# before
<match **>
@type forward
<server> host primary.example.com </server>
<secondary>
@type stdout
</secondary>
</match>
# after
<match **>
@type forward
<server> host primary.example.com </server>
<secondary>
@type secondary_file
directory /var/log/fluent/backup
</secondary>
</match> Defensive patterns
Strategy: validation
Validate before calling
# Catch it before deploy — all these fire during #configure fluentd --dry-run -c /etc/fluent/fluent.conf || exit 1
Prevention
- Run `fluentd --dry-run` in CI on every config change
- Treat `secondary_file` as the default secondary; only swap in another buffered output after checking it implements write/try_write
- Never use stdout/copy/null as secondary — they are process-only
When it happens
Trigger: `<match>` uses a buffered primary (e.g. forward, file, s3) and the `<secondary>` block names a process-only output such as `@type stdout`, `@type null`, or `@type copy`. The secondary plugin is instantiated via `Plugin.new_output`, `acts_as_secondary` is called, and its own `configure` hits the `@as_secondary` check with `@buffering == false`.
Common situations: Users add `<secondary> @type stdout` hoping to print failed data to the console, or copy an example `<secondary>` from another plugin without checking that the type is buffered; also seen when porting v0.12-era configs where secondary semantics differed.
Related errors
- secondary plugin '#{self.class}' must support buffering, but
- Invalid <secondary> section for non-buffered plugin
- <secondary> section cannot have <buffer> section
- buffer path is not configured. specify 'path' in <buffer>
- This plugin can only be used in the <secondary> section
AI-assisted analysis of fluent/fluentd@dd45c6e18d (2026-08-21).
Data as JSON: /api/errors/cc73fe6e9051005f.
Report an issue: GitHub.