jnunemaker/httparty · error · ArgumentError

Cookies must be an object which responds to #to_hash

Error message

Cookies must be an object which responds to #to_hash

What it means

The class-level DSL method `cookies` raises ArgumentError unless its argument responds to #to_hash. The value is handed to default_cookies.add_cookies, which merges it into a CookieHash applied to every request, so only Hash-like input is accepted. Note that a CookieHash or a plain Hash both work because both respond to to_hash.

Source

Thrown at lib/httparty.rb:252

    # Allows setting HTTP headers to be used for each request.
    #
    #   class Foo
    #     include HTTParty
    #     headers 'Accept' => 'text/html'
    #   end
    def headers(h = nil)
      if h
        raise ArgumentError, 'Headers must be an object which responds to #to_hash' unless h.respond_to?(:to_hash)
        default_options[:headers] ||= {}
        default_options[:headers].merge!(h.to_hash)
      else
        default_options[:headers] || {}
      end
    end

    def cookies(h = {})
      raise ArgumentError, 'Cookies must be an object which responds to #to_hash' unless h.respond_to?(:to_hash)
      default_cookies.add_cookies(h)
    end

    # Proceed to the location header when an HTTP response dictates a redirect.
    # Redirects are always followed by default.
    #
    # @example
    #   class Foo
    #     include HTTParty
    #     base_uri 'http://google.com'
    #     follow_redirects true
    #   end
    def follow_redirects(value = true)
      default_options[:follow_redirects] = value
    end

    # Allows setting the format with which to parse.
    # Must be one of the allowed formats ie: json, xml

View on GitHub (pinned to 8f4a09e343)

Solutions

  1. Pass name/value pairs as a Hash: `cookies sessionid: 'abc123'`.
  2. Convert a raw cookie string: `cookies Hash[raw.split('; ').map { |c| c.split('=', 2) }]`.
  3. Keep cookies from a prior response: assign `cookies response.headers['Set-Cookie']` only after parsing it, or use the cookie_hash from the response object.

Example fix

# before
cookies 'sessionid=abc123; theme=dark'   # String -> ArgumentError

# after
cookies 'sessionid' => 'abc123', 'theme' => 'dark'
Defensive patterns

Strategy: validation

Validate before calling

raise ArgumentError, 'cookies must be a Hash' unless jar.respond_to?(:to_hash)
cookies jar.to_hash

Type guard

hash_like = ->(v) { v.respond_to?(:to_hash) }

Try / catch

begin
  cookies jar
rescue ArgumentError
  raise ConfigError, 'pass cookies as { "name" => "value" }, not a Cookie header string'
end

Prevention

When it happens

Trigger: `cookies 'sessionid=abc123'` (raw Cookie-header string) inside a class that includes HTTParty, or `cookies nil`, `cookies [:a, :b]` at class level. Distinct from the per-request `get url, cookies: { ... }` option, which flows through the same guard when merged.

Common situations: Developers pasting a browser Cookie header string from devtools, loading cookie jars from JSON/YAML without parsing, and assuming Set-Cookie strings can be replayed directly.

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


AI-assisted analysis of jnunemaker/httparty@8f4a09e343 (2026-08-21). Data as JSON: /api/errors/4fc37c12e9837003. Report an issue: GitHub.