bblimke/webmock · error · ArgumentError
Key was repeated: #{key.inspect}
Error message
Key was repeated: #{key.inspect} What it means
With notation :flat, QueryMapper maps each query-string key to a single scalar value; a repeated key (a=1&a=2) cannot be represented in that shape, so fill_accumulator_for_flat raises ArgumentError naming the duplicated key. The query string itself is legal - this is a data-shape conflict between the input and the chosen notation, not a parse failure.
Source
Thrown at lib/webmock/util/query_mapper.rb:97
end
def collect_query_hash(query_array, empty_accumulator, options)
query_array.compact.inject(empty_accumulator.dup) do |accumulator, (key, value)|
value = if value.nil?
nil
else
::Addressable::URI.unencode_component(value.tr('+', ' '))
end
key = Addressable::URI.unencode_component(key)
key = key.dup.force_encoding(Encoding::ASCII_8BIT) if key.respond_to?(:force_encoding)
self.__send__("fill_accumulator_for_#{options[:notation]}", accumulator, key, value)
accumulator
end
end
def fill_accumulator_for_flat(accumulator, key, value)
if accumulator[key]
raise ArgumentError, "Key was repeated: #{key.inspect}"
end
accumulator[key] = value
end
def fill_accumulator_for_flat_array(accumulator, key, value)
accumulator << [key, value]
end
def fill_accumulator_for_dot(accumulator, key, value)
array_value = false
subkeys = key.split(".")
current_hash = accumulator
subkeys[0..-2].each do |subkey|
current_hash[subkey] = {} unless current_hash[subkey]
current_hash = current_hash[subkey]
end
if array_value
if current_hash[subkeys.last] && !current_hash[subkeys.last].is_a?(Array)View on GitHub (pinned to b187df8827)
Solutions
- Use notation :flat_array - it keeps duplicates as [key, value] pairs
- Use :subscript (the default), which folds repeated keys into an Array under one key
- De-duplicate the query string upstream when the repeated keys are unintended
Example fix
// before
values = WebMock::Util::QueryMapper.query_to_values('tag=ruby&tag=testing', notation: :flat)
# => ArgumentError: Key was repeated: tag
// after
values = WebMock::Util::QueryMapper.query_to_values('tag=ruby&tag=testing', notation: :flat_array)
# => [['tag', 'ruby'], ['tag', 'testing']] Defensive patterns
Strategy: validation
Validate before calling
def repeated_query_keys?(query)
keys = query.to_s.split('&').map { |pair| pair.split('=').first }
keys.size != keys.uniq.size
end
query = 'tag=ruby&tag=testing'
notation = repeated_query_keys?(query) ? :flat_array : :flat
values = WebMock::Util::QueryMapper.query_to_values(query, notation: notation) Prevention
- Default to :subscript or :flat_array; reserve :flat for queries you know have unique keys
- Check for duplicate keys before flattening third-party URLs
- When you control the client, encode arrays with bracket syntax (a[]=1) instead of repeated bare keys
When it happens
Trigger: WebMock::Util::QueryMapper.query_to_values('q=1&q=2', notation: :flat); URLs with repeated parameters (tag=ruby&tag=testing, duplicated utm_source) processed through :flat during URL normalization or by custom code built on QueryMapper.
Common situations: APIs that encode arrays as repeated bare keys (ids=1&ids=2) instead of bracket syntax; analytics/marketing URLs with duplicated utm parameters; switching from :subscript (the default) to :flat without checking the data; normalizing third-party URLs you do not control.
Related errors
- Invalid notation. Must be one of: [:flat, :dot, :subscript,
- #with method invoked with no arguments. Either options hash
- Wrong order. Use :before_local_stubs or :after_local_stubs
- Unknown key: #{k.inspect}. Valid keys are: #{valid_keys.map(
- Can't convert #{new_query_values.class} into Hash.
AI-assisted analysis of bblimke/webmock@b187df8827 (2026-08-23).
Data as JSON: /api/errors/960afb469b4e6662.
Report an issue: GitHub.