fluent/fluentd · error · Fluent::ConfigError

<buffer> section is configured, but plugin '#{self.class}' d

Error message

<buffer> section is configured, but plugin '#{self.class}' doesn't support buffering

What it means

Fluent::Plugin::Output#configure raises this Fluent::ConfigError when the config contains a `<buffer>` section for an output plugin that implements neither `buffered` (a #write method) nor `delayed_commit` (#try_write) processing — only synchronous #process. Buffering capability is determined by which processing methods the plugin class defines, so a `<buffer>` block on a process-only plugin is meaningless and rejected at startup.

Source

Thrown at lib/fluent/plugin/output.rb:270

        has_buffer_section = (conf.elements(name: 'buffer').size > 0)
        has_flush_interval = conf.has_key?('flush_interval')

        super

        @num_errors_metrics = metrics_create(namespace: "fluentd", subsystem: "output", name: "num_errors", help_text: "Number of count num errors")
        @emit_count_metrics = metrics_create(namespace: "fluentd", subsystem: "output", name: "emit_count", help_text: "Number of count emits")
        @emit_records_metrics = metrics_create(namespace: "fluentd", subsystem: "output", name: "emit_records", help_text: "Number of emit records")
        @emit_size_metrics =  metrics_create(namespace: "fluentd", subsystem: "output", name: "emit_size", help_text: "Total size of emit events")
        @write_count_metrics = metrics_create(namespace: "fluentd", subsystem: "output", name: "write_count", help_text: "Number of writing events")
        @write_secondary_count_metrics = metrics_create(namespace: "fluentd", subsystem: "output", name: "write_secondary_count", help_text: "Number of writing events in secondary")
        @rollback_count_metrics = metrics_create(namespace: "fluentd", subsystem: "output", name: "rollback_count", help_text: "Number of rollbacking operations")
        @flush_time_count_metrics = metrics_create(namespace: "fluentd", subsystem: "output", name: "flush_time_count", help_text: "Count of flush time")
        @slow_flush_count_metrics = metrics_create(namespace: "fluentd", subsystem: "output", name: "slow_flush_count", help_text: "Count of slow flush occurred time(s)")
        @drop_oldest_chunk_count_metrics = metrics_create(namespace: "fluentd", subsystem: "output", name: "drop_oldest_chunk_count", help_text: "Number of count that old chunk were discarded with drop_oldest_chunk")

        if has_buffer_section
          unless implement?(:buffered) || implement?(:delayed_commit)
            raise Fluent::ConfigError, "<buffer> section is configured, but plugin '#{self.class}' doesn't support buffering"
          end
          @buffering = true
        else # no buffer sections
          if implement?(:synchronous)
            if !implement?(:buffered) && !implement?(:delayed_commit)
              if @as_secondary
                raise Fluent::ConfigError, "secondary plugin '#{self.class}' must support buffering, but doesn't."
              end
              @buffering = false
            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

View on GitHub (pinned to dd45c6e18d)

Solutions

  1. Remove the <buffer> section — the plugin (e.g. out_copy) forwards events synchronously by design
  2. If you need buffering, wrap the target in a buffering-capable output (e.g. route to @type forward/file/http which implement #write) and put the sync plugin behind it
  3. Plugin authors: define #write(chunk) (buffered) or #try_write(chunk) + #commit_write (delayed commit) to accept <buffer>

Example fix

# before
<match **>
  @type copy
  <store> @type stdout </store>
  <buffer>            # out_copy supports only synchronous processing
    flush_interval 1s
  </buffer>
</match>

# after
<match **>
  @type copy
  <store> @type stdout </store>
</match>
# (buffer the buffered-capable stores individually if needed)
Defensive patterns

Strategy: type-guard

Validate before calling

# For plugin authors / test rigs: probe capabilities before accepting a <buffer> section
plugin = Fluent::Plugin.new_output('copy')
supports_buffering = plugin.implement?(:buffered) || plugin.implement?(:delayed_commit)
raise '<buffer> not supported by this plugin' if has_buffer_section && !supports_buffering

Type guard

# Type guard over plugin capabilities (Ruby)
def bufferable_output?(plugin_instance)
  plugin_instance.implement?(:buffered) || plugin_instance.implement?(:delayed_commit)
end

bufferable_output?(Fluent::Plugin.new_output('http'))  # => true  (defines #write)
bufferable_output?(Fluent::Plugin.new_output('copy'))  # => false (defines only #process)

Try / catch

# In config tooling:
begin
  Fluent::Test::Driver::Output.new(plugin).configure(conf_str)
rescue Fluent::ConfigError => e
  fail "buffer section rejected: #{e.message}"
end

Prevention

When it happens

Trigger: Adding `<buffer> ... </buffer>` to a synchronous-only output — stock examples: out_copy, out_relabel-style routers, most custom plugins that define only `process`. Configure fails before any data is processed.

Common situations: Users adding buffer/flush tuning to `<match> @type copy` hoping to smooth bursts; plugin authors forgetting to define #write; configs migrated from v0.12 buffered_* compat plugins.

Related errors


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