{"record":{"id":"5b5e1066bdef6556","repo":"fluent/fluentd","slug":"tag-must-be-a-string-tag-class","errorCode":null,"errorMessage":"tag must be a String: #{tag.class}","messagePattern":"tag must be a String: #(.+?)","errorType":"exception","errorClass":"ArgumentError","httpStatus":null,"severity":"error","filePath":"lib/fluent/plugin/output.rb","lineNumber":938,"sourceCode":"        @emit_count_metrics.inc\n        begin\n          execute_chunking(tag, es, enqueue: (@flush_mode == :immediate))\n          if !@retry && @buffer.queued?(nil, optimistic: true)\n            submit_flush_once\n          end\n        rescue\n          # TODO: separate number of errors into emit errors and write/flush errors\n          @num_errors_metrics.inc\n          raise\n        end\n      end\n\n      # TODO: optimize this code\n      def metadata(tag, time, record)\n        # this arguments are ordered in output plugin's rule\n        # Metadata 's argument order is different from this one (timekey, tag, variables)\n\n        raise ArgumentError, \"tag must be a String: #{tag.class}\" unless tag.nil? || tag.is_a?(String)\n        raise ArgumentError, \"time must be a Fluent::EventTime (or Integer): #{time.class}\" unless time.nil? || time.is_a?(Fluent::EventTime) || time.is_a?(Integer)\n        raise ArgumentError, \"record must be a Hash: #{record.class}\" unless record.nil? || record.is_a?(Hash)\n\n        if @chunk_keys.nil? && @chunk_key_time.nil? && @chunk_key_tag.nil?\n          # for tests\n          return Struct.new(:timekey, :tag, :variables).new\n        end\n\n        timekey = @chunk_key_time ? calculate_timekey(time) : nil\n        @_metadata_cache ||= MetadataCache.new\n\n        # timekey is int from epoch, and `timekey - timekey % 60` is assumed to mach with 0s of each minutes.\n        # it's wrong if timezone is configured as one which supports leap second, but it's very rare and\n        # we can ignore it (especially in production systems).\n        if @chunk_keys.empty?\n          return @_metadata_cache.metadata if @_metadata_cache.cached?(timekey: timekey, tag: tag)\n\n          meta = if @chunk_key_time && @chunk_key_tag","sourceCodeStart":920,"sourceCodeEnd":956,"githubUrl":"https://github.com/fluent/fluentd/blob/dd45c6e18dc7be33b5e5a0f0767bf46307ff5626/lib/fluent/plugin/output.rb#L920-L956","documentation":"Output#metadata (lib/fluent/plugin/output.rb:938) is the factory for Fluent::Plugin::Metadata objects used as buffer-chunk keys. It validates its arguments and raises ArgumentError unless tag is nil or a String. Plugin authors and test code call metadata directly; core fluentd normally passes the tag string emitted by inputs/routers, so seeing this error means a non-String tag object reached a buffered output's chunking layer.","triggerScenarios":"A custom output/filter plugin calling router/output.metadata(:event, time, record) or metadata(Object.new, ...); passing an Integer/Array tag; calling metadata with argument order swapped (e.g. record first) so a Hash lands in the tag slot.","commonSituations":"Writing a custom buffered output plugin or plugin tests that construct Metadata manually; refactoring a filter so a variable holding nil-or-symbol is passed as tag; copy-pasting code that assumed the Metadata.new(timekey, tag, variables) argument order instead of the metadata(tag, time, record) order.","solutions":["Pass a real Fluentd tag String like 'app.logs' (dot-separated) or nil.","Check argument order against metadata(tag, time, record) — note it differs from Metadata.new(timekey, tag, variables).","In tests, provide a string tag when emitting events through the plugin test driver instead of nil/symbol shortcuts."],"exampleFix":"# before\nmeta = output.metadata(record, time, nil) # record/Hash in tag slot -> ArgumentError\n# after\nmeta = output.metadata('app.logs', time, record)","handlingStrategy":"type-guard","validationCode":"tag = tag.to_s unless tag.is_a?(String) || tag.nil?\nmeta = output.metadata(tag, time, record)","typeGuard":"def valid_fluent_tag?(t)\n  t.is_a?(String) || t.nil?\nend","tryCatchPattern":"rescue ArgumentError => e\n  raise if e.message !~ /tag must be a String/\n  log.warn 'dropping event with malformed tag', tag_class: tag.class\n","preventionTips":["Remember metadata(tag, time, record) argument order — it differs from Metadata.new(timekey, tag, variables).","Always route events through router.emit(tag, time, record) which enforces types upstream.","In plugin tests, pass real string tags."],"tags":["fluentd","output-plugin","argument-validation","buffer"],"backgroundTag":"invalid-argument-type","analyzedSha":"dd45c6e18dc7be33b5e5a0f0767bf46307ff5626","analyzedAt":"2026-08-21T16:22:07.332Z","schemaVersion":2},"datasetVersion":"2026-08-21T18:17:14.833Z"}