puppetlabs/puppet · critical · Puppet::HTTP::RouteError
No more routes to #{name}
Error message
No more routes to #{name} What it means
After the session walks its resolver chain (SRV record resolver, then server_list resolver) without any resolver producing a usable service, it raises Puppet::HTTP::RouteError. This is the terminal failure of service discovery: no explicit URL was given, nothing was cached, and every configured discovery mechanism came up empty.
Source
Thrown at lib/puppet/http/session.rb:79
cached = @resolved_services[name]
return cached if cached
canceled = false
canceled_handler = ->(cancel) { canceled = cancel }
@resolvers.each do |resolver|
Puppet.debug("Resolving service '#{name}' using #{resolver.class}")
service = resolver.resolve(self, name, ssl_context: ssl_context, canceled_handler: canceled_handler)
if service
@resolved_services[name] = service
Puppet.debug("Resolved service '#{name}' to #{service.url}")
return service
elsif canceled
break
end
end
raise Puppet::HTTP::RouteError, "No more routes to #{name}"
end
# Collect per-site server versions. This will allow us to modify future
# requests based on the version of puppetserver we are talking to.
#
# @param [Puppet::HTTP::Response] response the request response containing headers
#
# @api private
def process_response(response)
version = response[Puppet::HTTP::HEADER_PUPPET_VERSION]
if version
site = Puppet::HTTP::Site.from_uri(response.url)
@server_versions[site] = version
end
end
# Determine if a session supports a capability. Depending on the server version
# we are talking to, we know certain features are available or not. TheseView on GitHub (pinned to e227c27540)
Solutions
- Run with --debug and read the 'Resolving service ... using' lines, then verify each candidate host:port is reachable (curl -k https://server:8140/status/v1/simple)
- Fix or remove dns_srv_domain and correct server_list so at least one route is valid
- Bypass discovery for one-offs by passing url: to route_to (explicit host and port skips resolvers)
- If a firewall or NAT is involved, open TCP 8140 to every master in server_list before retrying
Example fix
# before: dns_srv_domain = example.com with no SRV records, no server_list
session.route_to(:puppet) # => Puppet::HTTP::RouteError: No more routes to puppet
# after: puppet.conf -> server_list = puppet1.example.com,puppet2.example.com
session.route_to(:puppet)
# or explicit bypass (ruby):
session.route_to(:puppet, url: URI('https://puppet1.example.com:8140')) Defensive patterns
Strategy: try-catch
Validate before calling
# ruby
require 'socket'
reachable = Puppet[:server_list].split(',').any? do |h|
begin
TCPSocket.new(h.strip, Puppet[:serverport]).tap(&:close); true
rescue StandardError
false
end
end
raise 'no puppetserver reachable' unless reachable Type guard
def explicit_route?(url) url.is_a?(URI) && !url.host.nil? && !url.host.empty? end
Try / catch
begin service = session.route_to(:puppet) rescue Puppet::HTTP::RouteError => e Puppet.err(e.message) service = session.route_to(:puppet, url: KNOWN_MASTER_URI) # explicit fallback end
Prevention
- Keep server_list accurate and list more than one master for resilience
- Smoke-test TCP 8140 to each master during bootstrap; do not rely on SRV alone
- Pass an explicit url: to route_to in one-off scripts to bypass discovery
- Watch 'Resolving service' debug lines in integration tests to catch discovery regressions
When it happens
Trigger: dns_srv_domain is set and the SRV lookup yields no usable records while server_list is empty or all its entries fail their probe; every host:port candidate in server_list is unreachable (refused/timeout on 8140); the explicit url: bypass was not used.
Common situations: Wrong or stale server_list in puppet.conf; load balancer VIP down; firewall blocking TCP 8140; DNS SRV records (_x-puppet._tcp) deleted while dns_srv_domain remains set; TLS probe of each candidate failing during bootstrap before certificates are issued.
Related errors
- Could not back up %{file}: %{detail}
- Too many HTTP redirections for %{addr}
- The 'persistence' hash is missing the keys: #{missing.join('
- Facts must be a Hash not a #{facts.class}
- Path must start with a slash
AI-assisted analysis of puppetlabs/puppet@e227c27540 (2026-08-21).
Data as JSON: /api/errors/b5182bea2ce6c600.
Report an issue: GitHub.