{"record":{"id":"312856dd4d4c01f5","repo":"jnunemaker/httparty","slug":"query-must-be-hash-if-using-http-post","errorCode":null,"errorMessage":":query must be hash if using HTTP Post","messagePattern":":query must be hash if using HTTP Post","errorType":"exception","errorClass":"ArgumentError","httpStatus":null,"severity":"error","filePath":"lib/httparty/request.rb","lineNumber":421,"sourceCode":"    end\n\n    # Uses the HTTP Content-Type header to determine the format of the\n    # response It compares the MIME type returned to the types stored in the\n    # SupportedFormats hash\n    def format_from_mimetype(mimetype)\n      if mimetype && parser.respond_to?(:format_from_mimetype)\n        parser.format_from_mimetype(mimetype)\n      end\n    end\n\n    def validate\n      raise HTTParty::RedirectionTooDeep.new(last_response), 'HTTP redirects too deep' if options[:limit].to_i <= 0\n      raise ArgumentError, 'only get, post, patch, put, delete, head, and options methods are supported' unless SupportedHTTPMethods.include?(http_method)\n      raise ArgumentError, ':headers must be a hash' if options[:headers] && !options[:headers].respond_to?(:to_hash)\n      raise ArgumentError, 'only one authentication method, :basic_auth or :digest_auth may be used at a time' if options[:basic_auth] && options[:digest_auth]\n      raise ArgumentError, ':basic_auth must be a hash' if options[:basic_auth] && !options[:basic_auth].respond_to?(:to_hash)\n      raise ArgumentError, ':digest_auth must be a hash' if options[:digest_auth] && !options[:digest_auth].respond_to?(:to_hash)\n      raise ArgumentError, ':query must be hash if using HTTP Post' if post? && !options[:query].nil? && !options[:query].respond_to?(:to_hash)\n    end\n\n    def post?\n      Net::HTTP::Post == http_method\n    end\n\n    def set_basic_auth_from_uri\n      if path.userinfo\n        username, password = path.userinfo.split(':')\n        options[:basic_auth] = {username: username, password: password}\n        @credentials_sent = true\n      end\n    end\n\n    def decompress(body, encoding)\n      Decompressor.new(body, encoding).decompress\n    end\n","sourceCodeStart":403,"sourceCodeEnd":439,"githubUrl":"https://github.com/jnunemaker/httparty/blob/8f4a09e343b94de9f934f388028ca97620c9b378/lib/httparty/request.rb#L403-L439","documentation":"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.","triggerScenarios":"`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.","commonSituations":"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.","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:`."],"exampleFix":"# before\nFoo.post('http://x/search', query: 'q=ruby&page=2')   # String on POST -> ArgumentError\n\n# after\nFoo.post('http://x/search', query: { q: 'ruby', page: 2 })","handlingStrategy":"validation","validationCode":"if query && !query.respond_to?(:to_hash)\n  query = Hash[URI.decode_www_form(query)]  # or move it to body:\nend\nFoo.post(url, query: query)","typeGuard":"hash_like = ->(v) { v.respond_to?(:to_hash) }","tryCatchPattern":"begin\n  Foo.post(url, query: q)\nrescue ArgumentError => e\n  raise unless e.message.include?(':query')\n  Foo.post(url, query: Hash[URI.decode_www_form(q)])\nend","preventionTips":["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."],"tags":["ruby","httparty","validation","argument-error","query-params","http-post","request-options"],"backgroundTag":"invalid-argument-type","analyzedSha":"8f4a09e343b94de9f934f388028ca97620c9b378","analyzedAt":"2026-08-21T19:30:42.003Z","schemaVersion":2},"datasetVersion":"2026-08-22T04:17:13.399Z"}