fluent/fluentd · error · ArgumentError
Input must be a map (got #{record.class})
Error message
Input must be a map (got #{record.class}) What it means
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.
Source
Thrown at lib/fluent/command/cat.rb:171
@retry_wait = 1
@retry_limit = retry_limit
@time_as_integer = time_as_integer
@event_time = event_time
super()
end
def secondary_record?(record)
record.class != Hash &&
record.size == 2 &&
record.first.class == Fluent::EventTime &&
record.last.class == Hash
end
def write(record)
unless secondary_record?(record)
if record.class != Hash
raise ArgumentError, "Input must be a map (got #{record.class})"
end
end
time = if @event_time
Fluent::EventTime.parse(@event_time)
else
Fluent::EventTime.now
end
time = time.to_i if @time_as_integer
entry = if secondary_record?(record)
# Even though secondary contains Fluent::EventTime in record,
# fluent-cat just ignore it and set Fluent::EventTime.now instead.
# This specification is adopted to keep consistency.
[time, record.last]
else
[time, record]
end
synchronize {View on GitHub (pinned to dd45c6e18d)
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)
Example fix
# before
echo '[1, 2]' | fluent-cat test.tag # JSON array -> ArgumentError
# after
echo '{"one": 2}' | fluent-cat test.tag # one JSON object per line
echo 'plain text' | fluent-cat --none test.tag Defensive patterns
Strategy: type-guard
Validate before calling
records = lines.map { |l| JSON.parse(l) }.select { |r| r.is_a?(Hash) }
records.each { |r| writer.write(r) } Type guard
def fluent_cat_record?(obj)
obj.is_a?(Hash) ||
(obj.respond_to?(:size) && obj.size == 2 &&
obj.first.is_a?(Fluent::EventTime) && obj.last.is_a?(Hash))
end Try / catch
begin
writer.write(record)
rescue ArgumentError => e
raise unless e.message.start_with?('Input must be a map')
$stderr.puts "skipping non-object record: #{record.class}"
end Prevention
- 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
When it happens
Trigger: 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.
Common situations: 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.
Related errors
- unknown_key
- '#{capability}' is not valid capability. Valid Capabilities
- exceed retry limit
- Missing arguments
- Invalid contents (not object) in plugin storage file: '#{@pa
AI-assisted analysis of fluent/fluentd@dd45c6e18d (2026-08-21).
Data as JSON: /api/errors/b6e3ffa9ca1d1c8c.
Report an issue: GitHub.