puppetlabs/puppet · error · Puppet::Network::HTTP::Error::HTTPBadRequestError
No support for plurality %{indirection} for %{http_method} o
Error message
No support for plurality %{indirection} for %{http_method} operations What it means
After the verb check, the handler computes plurality(indirection) (plural for search-style paths such as facts or statuses) and looks up METHOD_MAP[http_method][plurality]. In this METHOD_MAP, GET supports both plural (search) and singular (find), while POST, PUT and DELETE define only singular entries. A verb applied to the wrong plurality therefore returns HTTP 400 naming the plurality and verb.
Source
Thrown at lib/puppet/network/http/api/indirected_routes.rb:244
return model_class.convert_from(formatter.name.to_s, data)
rescue => e
raise Puppet::Network::HTTP::Error::HTTPBadRequestError, _("The request body is invalid: %{message}") % { message: e.message }
end
end
# TRANSLATORS "mime-type" is a keyword and should not be translated
raise Puppet::Network::HTTP::Error::HTTPUnsupportedMediaTypeError.new(
_("Client sent a mime-type (%{header}) that doesn't correspond to a format we support") % { header: request.headers['content-type'] },
Puppet::Network::HTTP::Issues::UNSUPPORTED_MEDIA_TYPE
)
end
def indirection_method(http_method, indirection)
raise Puppet::Network::HTTP::Error::HTTPMethodNotAllowedError, _("No support for http method %{http_method}") % { http_method: http_method } unless METHOD_MAP[http_method]
method = METHOD_MAP[http_method][plurality(indirection)]
unless method
raise Puppet::Network::HTTP::Error::HTTPBadRequestError, _("No support for plurality %{indirection} for %{http_method} operations") % { indirection: plurality(indirection), http_method: http_method }
end
method
end
def self.pluralize(indirection)
(indirection == "status" ? "statuses" : indirection + "s")
end
private_class_method :pluralize
def plurality(indirection)
# NOTE These specific hooks for paths are ridiculous, but it's a *many*-line
# fix to not need this, and our goal is to move away from the complication
# that leads to the fix being too long.
return :singular if indirection == "facts"
return :singular if indirection == "status"
return :singular if indirection == "certificate_status"
View on GitHub (pinned to e227c27540)
Solutions
- Save data against the singular form: PUT /puppet/v3/facts/<certname>
- Use GET on plural paths only where METHOD_MAP defines :search (facts, statuses)
- Read METHOD_MAP at the top of lib/puppet/network/http/api/indirected_routes.rb for the authoritative verb/plurality pairs
Example fix
# before: saving to the plural form curl -X POST -H 'Content-Type: application/json' -d @facts.json \ "https://puppet:8140/puppet/v3/facts?environment=production" # after: save via PUT on the singular form curl -X PUT -H 'Content-Type: application/json' -d @facts.json \ "https://puppet:8140/puppet/v3/facts/mynode?environment=production"
Defensive patterns
Strategy: validation
Validate before calling
METHOD_MAP = {
'GET' => { plural: :search, singular: :find },
'POST' => { singular: :find },
'PUT' => { singular: :save },
'DELETE' => { singular: :destroy }
}.freeze
def verb_supported?(verb, plural)
!METHOD_MAP.dig(verb, plural ? :plural : :singular).nil?
end
raise ArgumentError, "#{verb} not valid for #{'im' unless plural}plural form" unless verb_supported?(verb, plural) Prevention
- Memorize the pattern: reads are GET (plural=search, singular=find), saves are PUT on the singular form, deletes are singular
- Write client helpers that encode the allowed verb/plurality pairs once
When it happens
Trigger: PUT or POST to /puppet/v3/facts (facts is plural; submission must be PUT /puppet/v3/facts/<certname>); DELETE against /puppet/v3/statuses; any save/destroy attempt against a plural/search path.
Common situations: Developers applying generic REST conventions where POST targets a collection; custom fact submitters using POST on the collection URL; adapting examples from other REST APIs without checking METHOD_MAP.
Related errors
- The indirection name must be purely alphanumeric, not '%{ind
- Indirection '%{indirection_name}' does not match url prefix
- An environment parameter must be specified
- No request key specified in %{uri}
- The request body is invalid: %{message}
AI-assisted analysis of puppetlabs/puppet@e227c27540 (2026-08-21).
Data as JSON: /api/errors/2ed82bfdec25e6a1.
Report an issue: GitHub.