{"record":{"id":"d9d4e5182a7a334e","repo":"fluent/fluentd","slug":"secondary-plugin-self-class-must-support-buff","errorCode":null,"errorMessage":"secondary plugin '#{self.class}' must support buffering, but doesn't.","messagePattern":"secondary plugin '#(.+?)' must support buffering, but doesn't\\.","errorType":"validation","errorClass":"Fluent::ConfigError","httpStatus":null,"severity":"error","filePath":"lib/fluent/plugin/output.rb","lineNumber":277,"sourceCode":"        @emit_records_metrics = metrics_create(namespace: \"fluentd\", subsystem: \"output\", name: \"emit_records\", help_text: \"Number of emit records\")\n        @emit_size_metrics =  metrics_create(namespace: \"fluentd\", subsystem: \"output\", name: \"emit_size\", help_text: \"Total size of emit events\")\n        @write_count_metrics = metrics_create(namespace: \"fluentd\", subsystem: \"output\", name: \"write_count\", help_text: \"Number of writing events\")\n        @write_secondary_count_metrics = metrics_create(namespace: \"fluentd\", subsystem: \"output\", name: \"write_secondary_count\", help_text: \"Number of writing events in secondary\")\n        @rollback_count_metrics = metrics_create(namespace: \"fluentd\", subsystem: \"output\", name: \"rollback_count\", help_text: \"Number of rollbacking operations\")\n        @flush_time_count_metrics = metrics_create(namespace: \"fluentd\", subsystem: \"output\", name: \"flush_time_count\", help_text: \"Count of flush time\")\n        @slow_flush_count_metrics = metrics_create(namespace: \"fluentd\", subsystem: \"output\", name: \"slow_flush_count\", help_text: \"Count of slow flush occurred time(s)\")\n        @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\")\n\n        if has_buffer_section\n          unless implement?(:buffered) || implement?(:delayed_commit)\n            raise Fluent::ConfigError, \"<buffer> section is configured, but plugin '#{self.class}' doesn't support buffering\"\n          end\n          @buffering = true\n        else # no buffer sections\n          if implement?(:synchronous)\n            if !implement?(:buffered) && !implement?(:delayed_commit)\n              if @as_secondary\n                raise Fluent::ConfigError, \"secondary plugin '#{self.class}' must support buffering, but doesn't.\"\n              end\n              @buffering = false\n            else\n              if @as_secondary\n                # secondary plugin always works as buffered plugin without buffer instance\n                @buffering = true\n              else\n                # @buffering.nil? shows that enabling buffering or not will be decided in lazy way in #start\n                @buffering = nil\n              end\n            end\n          else # buffered or delayed_commit is supported by `unless` of first line in this method\n            @buffering = true\n          end\n        end\n        # Enable to update record size metrics or not\n        @enable_size_metrics = !!system_config.enable_size_metrics\n","sourceCodeStart":259,"sourceCodeEnd":295,"githubUrl":"https://github.com/fluent/fluentd/blob/dd45c6e18dc7be33b5e5a0f0767bf46307ff5626/lib/fluent/plugin/output.rb#L259-L295","documentation":"Fluent::Plugin::Output#configure raises this Fluent::ConfigError when a plugin used inside `<secondary>` supports only synchronous processing (implements #process but neither #write nor #try_write). A secondary plugin receives already-buffered chunks from the failed primary and must flush them itself via #write, so a synchronous-only plugin cannot fulfill the role — unlike error 198, this fires even without a <buffer> section in the secondary itself, because secondaries always operate in buffered mode without their own buffer instance.","triggerScenarios":"`<secondary> @type copy ... </secondary>` (out_copy defines only #process — the canonical trigger), or any process-only custom plugin placed in <secondary>. Note @type file, secondary_file, stdout, null are buffered-capable and fine.","commonSituations":"Trying to fan out failed chunks to multiple destinations with copy inside <secondary>; promoting a custom sync plugin to secondary duty during incident response; misreading the secondary docs' plugin list.","solutions":["Use a buffering-capable plugin in <secondary>: @type file, @type secondary_file (the purpose-built one), or a network output implementing #write","To fan out failed chunks, make the primary's normal path handle fan-out (copy in the <match>) and keep the secondary simple","Plugin authors: implement #write(chunk) so the plugin qualifies as buffered"],"exampleFix":"# before\n<secondary>\n  @type copy           # copy is process-only; secondary must implement write\n  <store> @type stdout </store>\n</secondary>\n\n# after\n<secondary>\n  @type file\n  path /var/log/fluent/failed\n</secondary>","handlingStrategy":"type-guard","validationCode":"# Validate secondary candidates before deploying config\nsecondary_type = secondary_elem['@type']\nplugin = Fluent::Plugin.new_output(secondary_type)\nunless plugin.implement?(:buffered) || plugin.implement?(:delayed_commit)\n  raise \"#{secondary_type} cannot be used in <secondary>: it does not support buffering\"\nend","typeGuard":"# Type guard for secondary eligibility (Ruby)\ndef secondary_capable?(output_type)\n  p = Fluent::Plugin.new_output(output_type)\n  p.implement?(:buffered) || p.implement?(:delayed_commit)\nend\n\nsecondary_capable?('file')           # => true\nsecondary_capable?('secondary_file') # => true\nsecondary_capable?('copy')           # => false (process-only)","tryCatchPattern":"# In config tests:\nbegin\n  driver = Fluent::Test::Driver::Output.new(Fluent::Plugin::ForwardOutput)\n  driver.configure(fluent_conf_with_secondary)\nrescue Fluent::ConfigError => e\n  fail \"secondary rejected: #{e.message}\"\nend","preventionTips":["Reserve <secondary> for buffered-capable outputs (file, secondary_file, forward, http...); never copy","Smoke-test full <match> blocks including <secondary> with `fluentd --dry-run` in CI","Plugin authors: implementing #write(chunk) makes your plugin secondary-eligible; verify with an as_secondary configure test"],"tags":["fluentd","output-plugin","secondary","buffer","plugin-capability","configuration"],"backgroundTag":"secondary-plugin-not-buffered","analyzedSha":"dd45c6e18dc7be33b5e5a0f0767bf46307ff5626","analyzedAt":"2026-08-21T16:22:07.332Z","schemaVersion":2},"datasetVersion":"2026-08-21T18:17:14.833Z"}