lostisland/faraday · error · TypeError
Can't convert #{params.class} into Hash.
Error message
Can't convert #{params.class} into Hash. What it means
Faraday::FlatParamsEncoder.encode turns request params into a query string. It accepts nil, an Array of [key, value] pairs, or any object responding to #to_hash; every other input raises TypeError. The most common violation is passing an already-encoded query String where a Hash is expected, because String responds to neither #to_hash nor is it an Array of pairs.
Source
Thrown at lib/faraday/encoders/flat_params_encoder.rb:29
end
# Encode converts the given param into a URI querystring. Keys and values
# will converted to strings and appropriately escaped for the URI.
#
# @param params [Hash] query arguments to convert.
#
# @example
#
# encode({a: %w[one two three], b: true, c: "C"})
# # => 'a=one&a=two&a=three&b=true&c=C'
#
# @return [String] the URI querystring (without the leading '?')
def self.encode(params)
return nil if params.nil?
unless params.is_a?(Array)
unless params.respond_to?(:to_hash)
raise TypeError,
"Can't convert #{params.class} into Hash."
end
params = params.to_hash
params = params.map do |key, value|
key = key.to_s if key.is_a?(Symbol)
[key, value]
end
# Only to be used for non-Array inputs. Arrays should preserve order.
params.sort! if @sort_params
end
# The params have form [['key1', 'value1'], ['key2', 'value2']].
buffer = +''
params.each do |key, value|
encoded_key = escape(key)
if value.nil?
buffer << "#{encoded_key}&"View on GitHub (pinned to b25b1b26cc)
Solutions
- Pass a Hash: conn.get('https://api.example.com/search', q: 'ruby', page: 2).
- If you already hold an encoded query string, append it to the URL yourself instead of the params slot: conn.get("https://api.example.com/search?#{qs}") or build a URI and set uri.query.
- Pass an Array of pairs when you need repeated keys with ordering: conn.get(url, [%w[q ruby], %w[q rails]]).
- For custom param objects, define #to_hash on the class (or call .to_h on the caller side) so the encoder can convert it.
Example fix
# before
qs = URI.encode_www_form(q: 'ruby', page: 2)
conn.get('https://api.example.com/search', qs)
# => TypeError: Can't convert String into Hash.
# after
conn.get('https://api.example.com/search', q: 'ruby', page: 2)
# or, with a pre-built query string, put it in the URL:
conn.get("https://api.example.com/search?#{qs}") Defensive patterns
Strategy: type-guard
Validate before calling
params = nil unless params.is_a?(Hash) || params.is_a?(Array) || params.nil? conn.get(url, params)
Type guard
def encodable_params?(params) params.nil? || params.is_a?(Array) || params.respond_to?(:to_hash) end
Try / catch
begin
conn.get(url, params)
rescue TypeError => e
raise unless e.message.include?('into Hash')
conn.get(url, params.to_h) # last-resort conversion
end Prevention
- Treat the params argument as Hash-or-Array only; never pass a pre-encoded query string there.
- Put pre-built query strings into the URL ("#{url}?#{qs}") rather than the params slot.
- Add a sorbet/rbs signature or a cheap assert in debug builds: params.nil? || params.respond_to?(:to_hash).
When it happens
Trigger: Calling conn.get('https://api.example.com/search', 'q=ruby&page=2') — the second argument is params, not a query string; passing a JSON string, Integer, or arbitrary object as the params argument of get/post headers-level APIs; handing a custom config object to Faraday that does not implement #to_hash.
Common situations: Assuming the second argument to conn.get is a query string (it is a params Hash that gets encoded); porting code from libraries with a different signature; double-encoding bugs where the string then gets escaped again; passing a Struct or OpenStruct-like object that lacks #to_hash.
Related errors
- Can't convert #{params.class} into Hash.
- expected #{value_type.name} (got #{context[subkey].class.nam
- Expected :read, :write, :open. Got #{type.inspect} :(
- no stubbed request for #{env[:method]} #{env[:url]} #{env[:b
- unknown http method: #{method}
AI-assisted analysis of lostisland/faraday@b25b1b26cc (2026-08-21).
Data as JSON: /api/errors/f776472672d6ad98.
Report an issue: GitHub.