{"record":{"id":"8e8c4baeed4e3994","repo":"fluent/fluentd","slug":"unreloadable-plugin-fluent-plugin-lookup-type","errorCode":null,"errorMessage":"Unreloadable plugin: #{Fluent::Plugin.lookup_type_from_class(plugin.class)}, plugin_id: #{plugin.plugin_id}, class_name: #{plugin.class})","messagePattern":"Unreloadable plugin: #(.+?), plugin_id: #(.+?), class_name: #(.+?)\\)","errorType":"exception","errorClass":"Fluent::ConfigError","httpStatus":null,"severity":"error","filePath":"lib/fluent/engine.rb","lineNumber":189,"sourceCode":"      end\n\n      @root_agent_mutex.synchronize do\n        stop_phase(@root_agent)\n      end\n    end\n\n    # @param conf [Fluent::Config]\n    # @param supervisor [Bool]\n    # @return nil\n    def reload_config(conf, supervisor: false)\n      @root_agent_mutex.synchronize do\n        # configure first to reduce down time while restarting\n        new_agent = RootAgent.new(log: log, system_config: @system_config)\n        ret = Fluent::StaticConfigAnalysis.call(conf, workers: system_config.workers)\n\n        ret.all_plugins.each do |plugin|\n          if plugin.respond_to?(:reloadable_plugin?) && !plugin.reloadable_plugin?\n            raise Fluent::ConfigError, \"Unreloadable plugin: #{Fluent::Plugin.lookup_type_from_class(plugin.class)}, plugin_id: #{plugin.plugin_id}, class_name: #{plugin.class})\"\n          end\n        end\n\n        # Assign @root_agent to new root_agent\n        # for https://github.com/fluent/fluentd/blob/fcef949ce40472547fde295ddd2cfe297e1eddd6/lib/fluent/plugin_helper/event_emitter.rb#L50\n        old_agent, @root_agent = @root_agent, new_agent\n        begin\n          @root_agent.configure(conf)\n        rescue\n          @root_agent = old_agent\n          raise\n        end\n\n        unless @suppress_config_dump\n          $log.info :supervisor, \"using configuration file: #{conf.to_s.rstrip}\"\n        end\n\n        # supervisor doesn't handle actual data. so the following code is unnecessary.","sourceCodeStart":171,"sourceCodeEnd":207,"githubUrl":"https://github.com/fluent/fluentd/blob/dd45c6e18dc7be33b5e5a0f0767bf46307ff5626/lib/fluent/engine.rb#L171-L207","documentation":"On config reload (SIGHUP / reload RPC), Fluent::Engine.reload_config builds a new RootAgent and runs Fluent::StaticConfigAnalysis over the new conf; every plugin found must report reloadable_plugin? true or the reload is rejected with this ConfigError before the running agent is swapped. The old configuration keeps serving traffic (the engine restores the previous root agent on failure), so this is a reload-rejected error, not a crash. The message names the plugin type, its @id, and the class so the offender is identifiable.","triggerScenarios":"Sending SIGHUP (or invoking the config reload RPC) with a new config that contains a plugin whose class defines reloadable_plugin? false — typically certain input plugins and many third-party plugins; adding a brand-new non-reloadable plugin in an updated config; upgrading a plugin that dropped reload support.","commonSituations":"Using SIGHUP in deployment pipelines assuming zero-downtime reload; third-party plugins that never declared reload support; mixing a non-reloadable input into a previously reloadable pipeline.","solutions":["Do a full restart (stop + start) instead of SIGHUP for configs containing non-reloadable plugins","Identify the plugin from the message (type, plugin_id, class) and remove or replace it in the new config","Upgrade the plugin to a version that declares itself reloadable, or ask its maintainer to support reload","If you own the plugin, make it reload-safe and have it answer reloadable_plugin? with true"],"exampleFix":"# before: SIGHUP-based deploy with a non-reloadable plugin\nkill -HUP $(cat /var/run/fluentd.pid)   # reload rejected\n\n# after: restart when the config contains non-reloadable plugins\nsystemctl restart fluentd","handlingStrategy":"try-catch","validationCode":"# Pre-flight: static analysis of the new config before SIGHUP\nret = Fluent::StaticConfigAnalysis.call(new_conf, workers: 4)\nbad = ret.all_plugins.reject { |p| !p.respond_to?(:reloadable_plugin?) || p.reloadable_plugin? }\nabort 'reload would be rejected' unless bad.empty?","typeGuard":null,"tryCatchPattern":"begin\n  Fluent::Engine.reload_config(new_conf)\nrescue Fluent::ConfigError => e\n  log.warn \"config reload rejected, keeping previous config: #{e.message}\"\n  # old config keeps running; schedule a full restart instead\nend","preventionTips":["Treat SIGHUP reload as best-effort: deploy via full restart unless every plugin is known reloadable","Check plugin docs/changelogs for reload support before adding plugins to reloaded pipelines","Test reloads on staging with the production config"],"tags":["fluentd","reload","plugin-lifecycle","config"],"backgroundTag":"hot-reload-unsupported","analyzedSha":"dd45c6e18dc7be33b5e5a0f0767bf46307ff5626","analyzedAt":"2026-08-21T16:22:07.332Z","schemaVersion":2},"datasetVersion":"2026-08-21T18:17:14.833Z"}