{"record":{"id":"24dc9cdcb3979f36","repo":"jnunemaker/httparty","slug":"response","errorCode":null,"errorMessage":"#{response}","messagePattern":"#\\{response\\}","errorType":"exception","errorClass":"HTTParty::DuplicateLocationHeader","httpStatus":null,"severity":"error","filePath":"lib/httparty/request.rb","lineNumber":366,"sourceCode":"      end\n      if http_method == Net::HTTP::Get\n        clear_body\n      end\n      capture_cookies(last_response)\n      perform(&block)\n    end\n\n    def handle_host_redirection\n      check_duplicate_location_header\n      redirect_path = options[:uri_adapter].parse(last_response['location']).normalize\n      return if redirect_path.relative? || path.host == redirect_path.host || uri.host == redirect_path.host\n      @changed_hosts = true\n    end\n\n    def check_duplicate_location_header\n      location = last_response.get_fields('location')\n      if location.is_a?(Array) && location.count > 1\n        raise DuplicateLocationHeader.new(last_response)\n      end\n    end\n\n    def send_authorization_header?\n      !@changed_hosts\n    end\n\n    def response_redirects?\n      case last_response\n      when Net::HTTPNotModified # 304\n        false\n      when Net::HTTPRedirection\n        options[:follow_redirects] && last_response.key?('location')\n      end\n    end\n\n    def parse_response(body)\n      parser.call(body, format)","sourceCodeStart":348,"sourceCodeEnd":384,"githubUrl":"https://github.com/jnunemaker/httparty/blob/8f4a09e343b94de9f934f388028ca97620c9b378/lib/httparty/request.rb#L348-L384","documentation":"HTTParty raises HTTParty::DuplicateLocationHeader when it tries to follow a redirect and the response contains more than one Location header (last_response.get_fields('location') returns an array with count > 1). Duplicate Location headers make the redirect target ambiguous and are a classic sign of response splitting or a broken proxy, so HTTParty refuses to guess which one to follow. The exception inherits from HTTParty::ResponseError, so e.response holds the Net::HTTPResponse that triggered it; the message is just the response object rendered as a string, which is why it looks like \"#{response}\".","triggerScenarios":"Any request with follow_redirects enabled (the default) where the server answers 301/302/303/307/308 with two or more Location headers. check_duplicate_location_header runs inside handle_host_redirection before the redirect is parsed, e.g. `Foo.get('http://api.example.com/old')` against a host whose 302 response repeats Location twice.","commonSituations":"WebMock/VCR stubs that declare the Location header twice (once as a scalar and once in a with-headers hash), misconfigured nginx/HAProxy setups where both the backend and the proxy add Location, CDN edge rewrites that stack on top of origin redirects, and actual HTTP response-splitting from a vulnerable backend.","solutions":["Inspect e.response.headers.get_fields('location') in the rescue block to confirm the duplicate and see both values.","Fix the origin: ensure only one Location header is emitted on redirect responses (check proxy add_header/append and backend framework redirect helpers).","If the error comes from a test, fix the stub: WebMock `to_redirect('http://x/')` instead of hand-writing headers with multiple Location entries.","As a last resort, rescue HTTParty::DuplicateLocationHeader and treat it as a protocol error (retry without redirects via follow_redirects(false) and inspect manually)."],"exampleFix":"# before (server/stub sends two Location headers)\nstub_request(:get, 'http://api.example.com/old')\n  .to_return(status: 302, headers: { 'Location' => ['/a', '/b'] })\nFoo.get('http://api.example.com/old')\n# => HTTParty::DuplicateLocationHeader\n\n# after (exactly one Location header)\nstub_request(:get, 'http://api.example.com/old')\n  .to_return(status: 302, headers: { 'Location' => '/a' })\nFoo.get('http://api.example.com/old')","handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"begin\n  Foo.get('http://api.example.com/old')\nrescue HTTParty::DuplicateLocationHeader => e\n  locations = e.response.headers.get_fields('location')\n  Rails.logger.error(\"ambiguous redirect, #{locations.size} Location headers: #{locations.inspect}\")\n  raise\nend","preventionTips":["Stub exactly one Location header in WebMock/VCR redirect stubs.","Audit proxies/LBs (nginx add_header, HAPCRoxy http-response) so they replace, not append, Location on rewrites.","Treat DuplicateLocationHeader as a protocol/security signal in monitoring, not as a retryable error."],"tags":["ruby","httparty","redirect","http-headers","protocol-error","security"],"backgroundTag":"duplicate-http-header","analyzedSha":"8f4a09e343b94de9f934f388028ca97620c9b378","analyzedAt":"2026-08-21T19:30:42.003Z","schemaVersion":2},"datasetVersion":"2026-08-21T23:17:16.201Z"}