puppetlabs/puppet · error · Puppet::HTTP::SerializationError
HTTP REST queries cannot handle values of type '%{klass}'
Error message
HTTP REST queries cannot handle values of type '%{klass}' What it means
When Puppet::HTTP::Client encodes URL query parameters, arrays at the top level are expanded into repeated keys, but every leaf value must be nil, true/false, String, Symbol, Integer, or Float (client.rb:444). Any other class — Hash, Time, Date, Struct — raises Puppet::HTTP::SerializationError naming the class. Note nested Hashes are not expanded: a hash value goes straight to the primitive check.
Source
Thrown at lib/puppet/http/client.rb:447
value.collect { |val| [key, val] }
else
[key_value]
end
params.concat(expand_primitive_types_into_parameters(expanded_value))
end
end
def expand_primitive_types_into_parameters(data)
data.inject([]) do |params, key_value|
key, value = key_value
case value
when nil
params
when true, false, String, Symbol, Integer, Float
params << [key, value]
else
raise Puppet::HTTP::SerializationError, _("HTTP REST queries cannot handle values of type '%{klass}'") % { klass: value.class }
end
end
end
def encode_params(params)
params = expand_into_parameters(params)
params.map do |key, value|
"#{key}=#{Puppet::Util.uri_query_encode(value.to_s)}"
end.join('&')
end
def elapsed(start)
(Time.now - start).to_f.round(3)
end
def raise_error(message, cause, connected)
if connected
raise Puppet::HTTP::HTTPError.new(message, cause)View on GitHub (pinned to e227c27540)
Solutions
- Convert values to primitives yourself: since: Time.now.utc.iso8601.
- Flatten or serialize structured filters into strings before the call (e.g. JSON in a single param if the endpoint accepts it).
- For fully custom query strings, encode them into the URL yourself and pass params: {}.
Example fix
# before
client.get(url, params: { since: Time.now, environment: 'production' })
# after
client.get(url, params: { since: Time.now.utc.iso8601, environment: 'production' }) Defensive patterns
Strategy: type-guard
Validate before calling
params = params.transform_values { |v| case v when nil, true, false, String, Symbol, Integer, Float then v else v.to_s end }
client.get(url, params: params) Type guard
PRIMITIVES = [NilClass, TrueClass, FalseClass, String, Symbol, Integer, Float].freeze
param_safe = ->(v) { v.nil? || PRIMITIVES.any? { |c| v.is_a?(c) } }
params.each { |k, v| raise ArgumentError, "#{k} is not URL-encodable" unless param_safe.call(v) } Try / catch
begin client.get(url, params: params) rescue Puppet::HTTP::SerializationError => e retry_with = params.transform_values(&:to_s) client.get(url, params: retry_with) end
Prevention
- Convert Time/Date values to iso8601 strings before passing as params.
- Do not pass nested Hashes as query params — flatten or JSON-encode them into a single param.
When it happens
Trigger: client.get(url, params: { since: Time.now }); params: { filter: { kind: 'apply' } } (Hash value); params: { tags: [{ a: 1 }] } (hash inside an array); passing OpenStruct/Struct/BigDecimal objects from fact or report data.
Common situations: Query endpoints with timestamp filters where a Time object feels natural; structured filter hashes that the developer expects to be JSON-encoded; data flowing from YAML config where dates auto-parse into Date objects.
Related errors
- No format matches the given format name or mime-type (%{form
- #{path}: #{detail.message}
- Could not deserialize catalog from %{format}: %{detail}
- 'put' requires a string 'body' argument
- 'put' requires a 'content-type' header
AI-assisted analysis of puppetlabs/puppet@e227c27540 (2026-08-21).
Data as JSON: /api/errors/2af37f30ed213d6d.
Report an issue: GitHub.