{"record":{"id":"b6e3ffa9ca1d1c8c","repo":"fluent/fluentd","slug":"input-must-be-a-map-got-record-class","errorCode":null,"errorMessage":"Input must be a map (got #{record.class})","messagePattern":"Input must be a map \\(got #(.+?)\\)","errorType":"exception","errorClass":"ArgumentError","httpStatus":null,"severity":"error","filePath":"lib/fluent/command/cat.rb","lineNumber":171,"sourceCode":"    @retry_wait = 1\n    @retry_limit = retry_limit\n    @time_as_integer = time_as_integer\n    @event_time = event_time\n\n    super()\n  end\n\n  def secondary_record?(record)\n    record.class != Hash &&\n      record.size == 2 &&\n      record.first.class == Fluent::EventTime &&\n      record.last.class == Hash\n  end\n\n  def write(record)\n    unless secondary_record?(record)\n      if record.class != Hash\n        raise ArgumentError, \"Input must be a map (got #{record.class})\"\n      end\n    end\n\n    time = if @event_time\n             Fluent::EventTime.parse(@event_time)\n           else\n             Fluent::EventTime.now\n           end\n    time = time.to_i if @time_as_integer\n    entry = if secondary_record?(record)\n              # Even though secondary contains Fluent::EventTime in record,\n              # fluent-cat just ignore it and set Fluent::EventTime.now instead.\n              # This specification is adopted to keep consistency.\n              [time, record.last]\n            else\n              [time, record]\n            end\n    synchronize {","sourceCodeStart":153,"sourceCodeEnd":189,"githubUrl":"https://github.com/fluent/fluentd/blob/dd45c6e18dc7be33b5e5a0f0767bf46307ff5626/lib/fluent/command/cat.rb#L153-L189","documentation":"Raised as ArgumentError by Writer#write in fluent-cat. Each item parsed from stdin must be a Hash: by default one JSON object per line; with --msgpack an unpacked record; with --none the line is wrapped for you. The only non-Hash accepted shape is a two-element pair whose first element is a Fluent::EventTime and second is a Hash (msgpack secondary record). Any other JSON type (array, string, number, true/false/null) fails with the record's class in the message.","triggerScenarios":"echo '[1,2]' | fluent-cat test.tag or echo '\"hello\"' | fluent-cat test.tag (valid JSON but not an object); a producer emitting JSON arrays or scalars; a msgpack stream containing non-Hash objects; concatenating pretty-printed multi-line JSON.","commonSituations":"Piping jq output that is an array (jq '.items'); feeding NDJSON lines that are quoted strings; test harnesses sending raw numbers; msgpack dumps from other tools with mixed payload types.","solutions":["Send one JSON object per line: echo '{\"count\": 1}' | fluent-cat my.tag","For raw text use --none (each line becomes {\"message\": \"...\"}) and --message-key to rename the field","Fix the upstream producer: jq -c '.[]' or similar to stream objects instead of one array","For msgpack input, ensure every unpacked object is a Hash (or an EventTime/Hash pair)"],"exampleFix":"# before\necho '[1, 2]' | fluent-cat test.tag      # JSON array -> ArgumentError\n\n# after\necho '{\"one\": 2}' | fluent-cat test.tag    # one JSON object per line\necho 'plain text' | fluent-cat --none test.tag","handlingStrategy":"type-guard","validationCode":"records = lines.map { |l| JSON.parse(l) }.select { |r| r.is_a?(Hash) }\nrecords.each { |r| writer.write(r) }","typeGuard":"def fluent_cat_record?(obj)\n  obj.is_a?(Hash) ||\n    (obj.respond_to?(:size) && obj.size == 2 &&\n     obj.first.is_a?(Fluent::EventTime) && obj.last.is_a?(Hash))\nend","tryCatchPattern":"begin\n  writer.write(record)\nrescue ArgumentError => e\n  raise unless e.message.start_with?('Input must be a map')\n  $stderr.puts \"skipping non-object record: #{record.class}\"\nend","preventionTips":["Emit NDJSON objects (jq -c) rather than arrays or scalars","Use --none for raw text lines so fluent-cat wraps them into a Hash","Validate producer output shape once in a pipeline test"],"tags":["fluentd","fluent-cat","cli","json","input-validation"],"backgroundTag":"invalid-input-type","analyzedSha":"dd45c6e18dc7be33b5e5a0f0767bf46307ff5626","analyzedAt":"2026-08-21T16:22:07.332Z","schemaVersion":2},"datasetVersion":"2026-08-21T18:17:14.833Z"}