puppetlabs/puppet · error · Puppet::Util::YamlLoadError
#{path}: #{detail.message}
Error message
#{path}: #{detail.message} What it means
Puppet::Util::Yaml.safe_load wraps Psych.safe_load; when the document instantiates a class not listed in allowed_classes, Psych raises ::Psych::DisallowedClass and puppet re-raises it as YamlLoadError, prefixing the message with the filename (or (<unknown>)) and keeping the original as cause. Aliases are enabled (aliases: true), so anchors/aliases are fine — the guard is specifically about class tags.
Source
Thrown at lib/puppet/util/yaml.rb:38
#
# Attempting to deserialize other classes will raise an YamlLoadError
# exception unless they are specified in the array of *allowed_classes*.
# @param [String] yaml The yaml content to parse.
# @param [Array] allowed_classes Additional list of classes that can be deserialized.
# @param [String] filename The filename to load from, used if an exception is raised.
# @raise [YamlLoadException] If deserialization fails.
# @return The parsed YAML, which can be Hash, Array or scalar types.
def self.safe_load(yaml, allowed_classes = [], filename = nil)
if Gem::Version.new(Psych::VERSION) >= Gem::Version.new('3.1.0')
data = YAML.safe_load(yaml, permitted_classes: allowed_classes, aliases: true, filename: filename)
else
data = YAML.safe_load(yaml, allowed_classes, [], true, filename)
end
data = false if data.nil?
data
rescue ::Psych::DisallowedClass => detail
path = filename ? "(#{filename})" : "(<unknown>)"
raise YamlLoadError.new("#{path}: #{detail.message}", detail)
rescue *YamlLoadExceptions => detail
raise YamlLoadError.new(detail.message, detail)
end
# Safely load the content from a file as YAML.
#
# @see Puppet::Util::Yaml.safe_load
def self.safe_load_file(filename, allowed_classes = [])
yaml = Puppet::FileSystem.read(filename, :encoding => 'bom|utf-8')
safe_load(yaml, allowed_classes, filename)
end
# Safely load the content from a file as YAML if
# contents are in valid format. This method does not
# raise error but returns `nil` when invalid file is
# given.
def self.safe_load_file_if_valid(filename, allowed_classes = [])
safe_load_file(filename, allowed_classes)View on GitHub (pinned to e227c27540)
Solutions
- Pass the classes you actually need: Puppet::Util::Yaml.safe_load_file(path, [Symbol]) (add Date etc. as required — the error names the rejected class)
- Regenerate the offending file from plain data: hashes, arrays, strings, integers only
- If you control the writer, stop emitting ruby tags — call to_yaml on plain data instead of dumping objects
- Use the filename prefix in the message to identify which file is poisoned when several are loaded
Example fix
# before
Puppet::Util::Yaml.safe_load_file('/etc/puppet/extra.yaml')
# YamlLoadError: (/etc/puppet/extra.yaml): Tried to load unspecified class: Symbol
# after
Puppet::Util::Yaml.safe_load_file('/etc/puppet/extra.yaml', [Symbol]) Defensive patterns
Strategy: validation
Validate before calling
text = File.read(path) if text.match?(/^.*!ruby\//) # document contains class tags; decide allowed classes up front end Puppet::Util::Yaml.safe_load(text, [Symbol], path)
Try / catch
begin
Puppet::Util::Yaml.safe_load_file(path, allowed)
rescue Puppet::Util::YamlLoadError => e
# e.cause is the Psych::DisallowedClass naming the rejected class
raise "untrusted YAML in #{path}: #{e.message}"
end Prevention
- Serialize plain data (Hash/Array/String/Integer) — never Psych.dump objects that must round-trip through safe_load
- Pass the exact allowed_classes list you need ([Symbol] covers most puppet data)
- Prefer writing YAML with to_yaml on plain structures so no ruby tags ever appear
When it happens
Trigger: Loading YAML containing !ruby/symbol, !ruby/object, !ruby/hash or similar tags while allowed_classes is empty (the default for safe_load_file callers); files written with unsafe Psych.dump on rich objects and later read through safe_load.
Common situations: State/cache files hand-edited or produced by another tool and read by puppet's safe_load_file; Psych 4's safe-by-default behavior surfacing after a Ruby upgrade; YAML exchanged between components where one side serializes rich objects.
Related errors
- Could not intern from %{format}: %{err}
- Could not intern_multiple from %{format}: %{err}
- Serialized YAML did not contain a valid instance of %{klass}
- Serialized YAML did not contain a collection of instances wh
- Serialized YAML did not contain a valid instance of %{klass}
AI-assisted analysis of puppetlabs/puppet@e227c27540 (2026-08-21).
Data as JSON: /api/errors/7698e7985ca99814.
Report an issue: GitHub.