{"record":{"id":"a2786388196fc43c","repo":"imathis/octopress","slug":"github-replied-with-a-302-but-didn-t-provide-a-loc","errorCode":null,"errorMessage":"GitHub replied with a 302 but didn't provide a location in the response headers.","messagePattern":"GitHub replied with a 302 but didn't provide a location in the response headers\\.","errorType":"exception","errorClass":"ArgumentError","httpStatus":null,"severity":"error","filePath":"plugins/gist_tag.rb","lineNumber":99,"sourceCode":"      locations = Array.new\n      while (data.code.to_i == 301 || data.code.to_i == 302)\n        data = handle_gist_redirecting(data)\n        break if locations.include? data.header['Location']\n        locations << data.header['Location']\n      end\n\n      if data.code.to_i != 200\n        raise RuntimeError, \"Gist replied with #{data.code} for #{gist_url}\"\n      end\n\n      cache(gist, file, data.body) unless @cache_disabled\n      data.body\n    end\n\n    def handle_gist_redirecting(data)\n      redirected_url = data.header['Location']\n      if redirected_url.nil? || redirected_url.empty?\n        raise ArgumentError, \"GitHub replied with a 302 but didn't provide a location in the response headers.\"\n      end\n\n      get_web_content(redirected_url)\n    end\n\n    def get_web_content(url)\n      raw_uri           = URI.parse url\n      proxy             = ENV['http_proxy']\n      if proxy\n        proxy_uri       = URI.parse(proxy)\n        https           = Net::HTTP::Proxy(proxy_uri.host, proxy_uri.port).new raw_uri.host, raw_uri.port\n      else\n        https           = Net::HTTP.new raw_uri.host, raw_uri.port\n      end\n      https.use_ssl     = true\n      https.verify_mode = OpenSSL::SSL::VERIFY_NONE\n      request           = Net::HTTP::Get.new raw_uri.request_uri\n      data              = https.request request","sourceCodeStart":81,"sourceCodeEnd":117,"githubUrl":"https://github.com/imathis/octopress/blob/5717a50f4e4964ea8423997d6456b04c653f0348/plugins/gist_tag.rb#L81-L117","documentation":"ArgumentError raised in handle_gist_redirecting (gist_tag.rb:96-100) when a response arrives with code 301/302 but the Location header is nil or empty. Something announced a redirect yet gave no destination, so the plugin cannot follow it. Genuine GitHub responses always carry a Location header, so this almost always implicates an intermediary: the ENV['http_proxy'] proxy wired in by get_web_content, a captive portal, or an SSL-inspecting middlebox — the plugin sets verify_mode = OpenSSL::SSL::VERIFY_NONE (line 115), so interception is accepted silently. It propagates out of the Liquid tag and aborts the Jekyll build.","triggerScenarios":"ENV['http_proxy'] pointing at a proxy that answers 302 without a Location header; a captive portal or transparent proxy intercepting the HTTPS request to gist.githubusercontent.com; any garbled or truncated response where data.header['Location'] resolves to nil. Only reachable when the first or a chained response's code is 301/302.","commonSituations":"CI runners exporting a generic http_proxy; corporate networks with SSL-inspecting appliances; building the site on hotel/airport wifi behind a captive portal; rare load-balancer misconfigurations during a GitHub incident.","solutions":["Unset or fix the proxy before building: env -u http_proxy -u https_proxy jekyll build (also check CI environment variable settings)","Confirm direct reachability: curl -sI https://gist.githubusercontent.com/raw/<id>/<file> should show 301/302 WITH a Location line","Commit a populated .gist-cache so builds take the cached path and never follow redirects","Patch the redirect loop to skip Location-less redirects (see exampleFix) or switch to an HTTP client that follows redirects safely"],"exampleFix":"# before (plugins/gist_tag.rb:82-86)\nwhile (data.code.to_i == 301 || data.code.to_i == 302)\n  data = handle_gist_redirecting(data)\n  break if locations.include? data.header['Location']\n  locations << data.header['Location']\nend\n\n# after - a 302 with no Location is treated as a normal non-200 response\nwhile (data.code.to_i == 301 || data.code.to_i == 302) && !data.header['Location'].to_s.empty?\n  data = handle_gist_redirecting(data)\n  break if locations.include? data.header['Location']\n  locations << data.header['Location']\nend","handlingStrategy":"validation","validationCode":"# Check a redirect actually goes somewhere before following it\ndef followable_redirect?(response)\n  return false unless [301, 302].include?(response.code.to_i)\n  loc = response.header['Location'].to_s\n  return false if loc.strip.empty?\n  uri = URI.parse(loc) rescue nil\n  !uri.nil?\nend","typeGuard":null,"tryCatchPattern":"begin\n  data = get_web_content(gist_url)\nrescue ArgumentError => e\n  raise unless e.message.include?(\"didn't provide a location\")\n  warn \"Redirect without Location (proxy interference?) for #{gist_url}\"\n  next # or return \"<!-- gist #{gist} skipped: malformed redirect -->\"\nend","preventionTips":["Unset or correct http_proxy/https_proxy in CI before running jekyll build","Verify with curl -sI that 302 responses from gist.githubusercontent.com include a Location header","Commit .gist-cache so builds never follow redirects","Patch get_web_content to use OpenSSL::SSL::VERIFY_PEER so MITM proxies fail loudly instead of silently issuing bogus redirects"],"tags":["jekyll","http-redirect","proxy","network","ruby","gist"],"backgroundTag":"redirect-without-location","analyzedSha":"5717a50f4e4964ea8423997d6456b04c653f0348","analyzedAt":"2026-08-21T17:21:26.485Z","schemaVersion":2},"datasetVersion":"2026-08-21T18:17:14.833Z"}