puppetlabs/puppet · error · Puppet::HTTP::TooManyRedirects

Too many HTTP redirections for %{addr}

Error message

Too many HTTP redirections for %{addr}

What it means

Puppet::HTTP::Client follows 301/302/307 redirects through Puppet::HTTP::Redirector, counting each hop. When the hop count reaches the redirect limit — default 10, overridable per request via options[:redirect_limit] (client.rb:354) — it raises Puppet::HTTP::TooManyRedirects with the request URI in the message. This indicates a chain longer than allowed or a redirect loop.

Source

Thrown at lib/puppet/http/redirector.rb:46

    when 301, 302, 307
      true
    else
      false
    end
  end

  # Implement the HTTP request redirection
  #
  # @param [Net::HTTP] request request that has been redirected
  # @param [Puppet::HTTP::Response] response
  # @param [Integer] redirects the current number of redirects
  #
  # @return [Net::HTTP] A new request based on the original request, but with
  #   the redirected location
  #
  # @api private
  def redirect_to(request, response, redirects)
    raise Puppet::HTTP::TooManyRedirects, request.uri if redirects >= @redirect_limit

    location = parse_location(response)
    url = request.uri.merge(location)

    new_request = request.class.new(url)
    new_request.body = request.body
    request.each do |header, value|
      unless Puppet[:location_trusted]
        # skip adding potentially sensitive header to other hosts
        next if header.casecmp('Authorization').zero? && request.uri.host.casecmp(location.host) != 0
        next if header.casecmp('Cookie').zero? && request.uri.host.casecmp(location.host) != 0
      end
      # Allow Net::HTTP to set its own Accept-Encoding header to avoid errors with HTTP compression.
      # See https://github.com/puppetlabs/puppet/issues/9143
      next if header.casecmp('Accept-Encoding').zero?

      new_request[header] = value
    end

View on GitHub (pinned to e227c27540)

Solutions

  1. Reproduce with curl -ILv <url> and count the hops: fix the server-side rewrite loop first.
  2. Ensure redirect targets are final URLs (correct scheme/host/port) rather than re-entering the redirect rule.
  3. If the chain is legitimately longer than 10, raise options[:redirect_limit] on the specific request instead of globally.
  4. Check proxy PreserveHost/redirect rules when a load balancer sits in front of the compiler/CA.

Example fix

# before
response = client.get(uri)

# after - allow a longer (but still bounded) chain for this request
response = client.get(uri, options: { redirect_limit: 20 })
Defensive patterns

Strategy: try-catch

Try / catch

begin
  response = client.get(uri)
rescue Puppet::HTTP::TooManyRedirects => e
  # e.message includes the original request URI
  Puppet.err "redirect budget exhausted for #{uri}; verify server/proxy rewrites"
  raise
end

Prevention

When it happens

Trigger: A redirect chain (A→B→C…) longer than redirect_limit; a loop such as https→https rewrites where hostnames alternate; a proxy redirecting to itself; count reaches the limit on the next redirect_to call because redirects >= @redirect_limit.

Common situations: Misconfigured reverse proxy or SSL terminator rewriting in a circle; CDN/LB redirect rules that drop the port; server_list entries pointing at a vhost that redirects to a login page that redirects back; captive portals.

Related errors


AI-assisted analysis of puppetlabs/puppet@e227c27540 (2026-08-21). Data as JSON: /api/errors/c10f27f0145c4ba8. Report an issue: GitHub.