{"record":{"id":"89ead00fbcdea5a6","repo":"jnunemaker/httparty","slug":"headers-must-be-an-object-which-responds-to-to-ha","errorCode":null,"errorMessage":"Headers must be an object which responds to #to_hash","messagePattern":"Headers must be an object which responds to #to_hash","errorType":"exception","errorClass":"ArgumentError","httpStatus":null,"severity":"error","filePath":"lib/httparty.rb","lineNumber":243,"sourceCode":"    # The output stream is passed on to Net::HTTP#set_debug_output.\n    #\n    #   class Foo\n    #     include HTTParty\n    #     debug_output $stderr\n    #   end\n    def debug_output(stream = $stderr)\n      default_options[:debug_output] = stream\n    end\n\n    # Allows setting HTTP headers to be used for each request.\n    #\n    #   class Foo\n    #     include HTTParty\n    #     headers 'Accept' => 'text/html'\n    #   end\n    def headers(h = nil)\n      if h\n        raise ArgumentError, 'Headers must be an object which responds to #to_hash' unless h.respond_to?(:to_hash)\n        default_options[:headers] ||= {}\n        default_options[:headers].merge!(h.to_hash)\n      else\n        default_options[:headers] || {}\n      end\n    end\n\n    def cookies(h = {})\n      raise ArgumentError, 'Cookies must be an object which responds to #to_hash' unless h.respond_to?(:to_hash)\n      default_cookies.add_cookies(h)\n    end\n\n    # Proceed to the location header when an HTTP response dictates a redirect.\n    # Redirects are always followed by default.\n    #\n    # @example\n    #   class Foo\n    #     include HTTParty","sourceCodeStart":225,"sourceCodeEnd":261,"githubUrl":"https://github.com/jnunemaker/httparty/blob/8f4a09e343b94de9f934f388028ca97620c9b378/lib/httparty.rb#L225-L261","documentation":"The class-level DSL method `headers` raises ArgumentError when given a value that does not respond to #to_hash. headers(h) merges the argument into default_options[:headers] for every request, so it must be a Hash or a Hash-like object; the guard fires at class-definition time, before any network traffic happens.","triggerScenarios":"`headers 'Accept: text/html'` (a raw header string instead of a Hash), `headers nil` passed explicitly (h is truthy-checked, but a non-hash truthy value raises), `headers JSON.generate(...)`, or `headers [[:accept, 'text/html']]` inside an HTTParty class.","commonSituations":"Copy-pasting a curl -H 'X: y' style string into the DSL, feeding headers read from a config file or ENV variable that arrives as a String, and mixing up this setter with the request-level `get url, headers: {...}` option.","solutions":["Pass a Hash with header names as keys: `headers 'Accept' => 'text/html'`.","Parse external header strings before the call: `headers Hash[raw.split(': ').map ...]` or store config as YAML/JSON and parse it to a Hash.","For one-off headers, use the per-request option instead: `Foo.get(url, headers: { 'Accept' => 'text/html' })`."],"exampleFix":"# before\nheaders 'Accept: application/json'   # String -> ArgumentError\n\n# after\nheaders 'Accept' => 'application/json'","handlingStrategy":"validation","validationCode":"raise ArgumentError, 'headers config must be a Hash' unless h.respond_to?(:to_hash)\nheaders h.to_hash","typeGuard":"hash_like = ->(v) { v.respond_to?(:to_hash) }","tryCatchPattern":"begin\n  headers h\nrescue ArgumentError\n  raise ConfigError, 'headers must be configured as a Hash, e.g. { \"Accept\" => \"application/json\" }'\nend","preventionTips":["Never paste raw 'Key: value' curl strings into the headers DSL.","Keep header config in YAML/JSON parsed to a Hash at load time.","Use per-request headers: hash for dynamic values."],"tags":["ruby","httparty","configuration","validation","argument-error","http-headers"],"backgroundTag":"invalid-argument-type","analyzedSha":"8f4a09e343b94de9f934f388028ca97620c9b378","analyzedAt":"2026-08-21T19:30:42.003Z","schemaVersion":2},"datasetVersion":"2026-08-21T23:17:16.201Z"}