jnunemaker/httparty · error · ArgumentError
:query must be hash if using HTTP Post
Error message
:query must be hash if using HTTP Post
What it means
Request#validate raises ArgumentError ':query must be hash if using HTTP Post' when a POST request carries a non-nil options[:query] that does not respond to #to_hash. For POST you normally want `body:`; the `query:` option exists for appending URL parameters and, on POST specifically, httparty requires it to be a Hash so it can be normalized into the query string unambiguously. GET/PUT/PATCH with a string query are not subject to this check.
Source
Thrown at lib/httparty/request.rb:421
end
# Uses the HTTP Content-Type header to determine the format of the
# response It compares the MIME type returned to the types stored in the
# SupportedFormats hash
def format_from_mimetype(mimetype)
if mimetype && parser.respond_to?(:format_from_mimetype)
parser.format_from_mimetype(mimetype)
end
end
def validate
raise HTTParty::RedirectionTooDeep.new(last_response), 'HTTP redirects too deep' if options[:limit].to_i <= 0
raise ArgumentError, 'only get, post, patch, put, delete, head, and options methods are supported' unless SupportedHTTPMethods.include?(http_method)
raise ArgumentError, ':headers must be a hash' if options[:headers] && !options[:headers].respond_to?(:to_hash)
raise ArgumentError, 'only one authentication method, :basic_auth or :digest_auth may be used at a time' if options[:basic_auth] && options[:digest_auth]
raise ArgumentError, ':basic_auth must be a hash' if options[:basic_auth] && !options[:basic_auth].respond_to?(:to_hash)
raise ArgumentError, ':digest_auth must be a hash' if options[:digest_auth] && !options[:digest_auth].respond_to?(:to_hash)
raise ArgumentError, ':query must be hash if using HTTP Post' if post? && !options[:query].nil? && !options[:query].respond_to?(:to_hash)
end
def post?
Net::HTTP::Post == http_method
end
def set_basic_auth_from_uri
if path.userinfo
username, password = path.userinfo.split(':')
options[:basic_auth] = {username: username, password: password}
@credentials_sent = true
end
end
def decompress(body, encoding)
Decompressor.new(body, encoding).decompress
end
View on GitHub (pinned to 8f4a09e343)
Solutions
- Pass a Hash: `Foo.post(url, query: { a: 1, b: 2 })`.
- Parse an existing string: `query: Hash[URI.decode_www_form(str)]`.
- If the string is the payload, move it to `body:` instead of `query:`.
Example fix
# before
Foo.post('http://x/search', query: 'q=ruby&page=2') # String on POST -> ArgumentError
# after
Foo.post('http://x/search', query: { q: 'ruby', page: 2 }) Defensive patterns
Strategy: validation
Validate before calling
if query && !query.respond_to?(:to_hash) query = Hash[URI.decode_www_form(query)] # or move it to body: end Foo.post(url, query: query)
Type guard
hash_like = ->(v) { v.respond_to?(:to_hash) } Try / catch
begin
Foo.post(url, query: q)
rescue ArgumentError => e
raise unless e.message.include?(':query')
Foo.post(url, query: Hash[URI.decode_www_form(q)])
end Prevention
- Use query: with Hashes only on POST; use body: for payloads.
- Shared verb helpers should normalize query args to Hash for all methods.
- When porting GET calls to POST, translate the query string, don't reuse it.
When it happens
Trigger: `Foo.post(url, query: 'a=1&b=2')`, `Foo.post(url, query: URI.decode_www_form(...))` (array of pairs), or copy-pasting a pre-built query string that worked with `get` into a `post` call.
Common situations: Moving a search-pagination call from GET to POST while keeping the query-string style, paginating API wrappers that pass through user-supplied query strings, and helper methods shared across verbs.
Understand the failure class
Background: Invalid argument type errors: "must be of type string", "expected X, got Y", and ERR_INVALID_ARG_TYPE explained — this error's family across 15 libraries.
Related errors
- Default params must be an object which responds to #to_hash
- :headers must be a hash
- :basic_auth must be a hash
- :digest_auth must be a hash
- Headers must be an object which responds to #to_hash
AI-assisted analysis of jnunemaker/httparty@8f4a09e343 (2026-08-21).
Data as JSON: /api/errors/312856dd4d4c01f5.
Report an issue: GitHub.