puppetlabs/puppet · error · Puppet::Network::HTTP::Error::HTTPBadRequestError
Indirection '%{indirection_name}' does not match url prefix
Error message
Indirection '%{indirection_name}' does not match url prefix '%{url_prefix}' What it means
Puppet's indirected REST routes validate that the URL prefix of a request matches the indirection being requested. IndirectionType maps certificate, certificate_request, certificate_status and certificate_revocation_list to the 'puppet-ca/v1' prefix and everything else to 'puppet/v3'. When the handler receives a mismatched pair, it rejects the request with HTTP 400 before the indirection is ever consulted.
Source
Thrown at lib/puppet/network/http/api/indirected_routes.rb:74
end
def uri2indirection(http_method, uri, params)
# the first field is always nil because of the leading slash,
indirection_type, version, indirection_name, key = uri.split("/", 5)[1..]
url_prefix = "/#{indirection_type}/#{version}"
environment = params.delete(:environment)
if indirection_name !~ /^\w+$/
raise Puppet::Network::HTTP::Error::HTTPBadRequestError, _("The indirection name must be purely alphanumeric, not '%{indirection_name}'") % { indirection_name: indirection_name }
end
# this also depluralizes the indirection_name if it is a search
method = indirection_method(http_method, indirection_name)
# check whether this indirection matches the prefix and version in the
# request
if url_prefix != IndirectionType.url_prefix_for(indirection_name)
raise Puppet::Network::HTTP::Error::HTTPBadRequestError, _("Indirection '%{indirection_name}' does not match url prefix '%{url_prefix}'") % { indirection_name: indirection_name, url_prefix: url_prefix }
end
indirection = Puppet::Indirector::Indirection.instance(indirection_name.to_sym)
unless indirection
raise Puppet::Network::HTTP::Error::HTTPNotFoundError.new(
_("Could not find indirection '%{indirection_name}'") % { indirection_name: indirection_name },
Puppet::Network::HTTP::Issues::HANDLER_NOT_FOUND
)
end
unless environment
raise Puppet::Network::HTTP::Error::HTTPBadRequestError, _("An environment parameter must be specified")
end
unless Puppet::Node::Environment.valid_name?(environment)
raise Puppet::Network::HTTP::Error::HTTPBadRequestError, _("The environment must be purely alphanumeric, not '%{environment}'") % { environment: environment }
end
View on GitHub (pinned to e227c27540)
Solutions
- Use the correct prefix: certificate, certificate_request, certificate_status, certificate_revocation_list go under /puppet-ca/v1/..., all other indirections under /puppet/v3/...
- Check proxy and rewrite rules in front of the Puppet master so the full /puppet/v3 or /puppet-ca/v1 path reaches the handler intact
- When writing a custom handler, register routes via Puppet::Network::HTTP::Route.path('/puppet') vs Route.path('/puppet-ca') to match the indirections you serve
- Enable Puppet debug logging ('Routes Registered') to see the exact url_prefix the handler receives for the failing request
Example fix
# before curl -k "https://puppet.example.com:8140/puppet/v3/certificate/ca?environment=production" # after # -k "https://puppet.example.com:8140/puppet-ca/v1/certificate/ca?environment=production"
Defensive patterns
Strategy: validation
Validate before calling
CA_INDIRECTIONS = %w[certificate certificate_request certificate_status certificate_revocation_list].freeze
def prefix_for(indirection)
CA_INDIRECTIONS.include?(indirection) ? 'puppet-ca/v1' : 'puppet/v3'
end
def indirected_uri(indirection, key)
"/#{prefix_for(indirection)}/#{indirection}/#{key}"
end Prevention
- Derive the URL prefix from the indirection name instead of hardcoding /puppet
- Prefer Puppet's own client (Puppet.runtime[:http] or puppet agent) over hand-rolled HTTP calls
- Keep fronting proxies from rewriting the /puppet or /puppet-ca path segments
When it happens
Trigger: Requesting a CA indirection under the master prefix, e.g. GET /puppet/v3/certificate/ca, or a master indirection under the CA prefix, e.g. GET /puppet-ca/v1/catalog/mynode. Also produced by custom mounts or reverse proxies that rewrite the /puppet/v3 or /puppet-ca/v1 path segments so url_prefix no longer equals IndirectionType.url_prefix_for(indirection_name).
Common situations: Hand-written curl or rest-client calls that hardcode '/puppet' for every endpoint; middleware/proxies stripping or rewriting the versioned path prefix; scripts ported from the legacy v2 URL scheme (/production/catalog/...) that guess the new prefix; custom Rack/WEBrick servers registering routes with the wrong prefix for the served indirections.
Related errors
- The indirection name must be purely alphanumeric, not '%{ind
- An environment parameter must be specified
- No request key specified in %{uri}
- The request body is invalid: %{message}
- No support for plurality %{indirection} for %{http_method} o
AI-assisted analysis of puppetlabs/puppet@e227c27540 (2026-08-21).
Data as JSON: /api/errors/c382843633c88f38.
Report an issue: GitHub.