{"record":{"id":"84ae81202fd41009","repo":"puppetlabs/puppet","slug":"could-not-parse-yaml-data-for-indirection-req","errorCode":null,"errorMessage":"Could not parse YAML data for %{indirection} %{request}: %{detail}","messagePattern":"Could not parse YAML data for %(.+?) %(.+?): %(.+?)","errorType":"exception","errorClass":"Puppet::Error","httpStatus":null,"severity":"error","filePath":"lib/puppet/indirector/yaml.rb","lineNumber":16,"sourceCode":"# frozen_string_literal: true\n\nrequire_relative '../../puppet/indirector/terminus'\nrequire_relative '../../puppet/util/yaml'\n\n# The base class for YAML indirection termini.\nclass Puppet::Indirector::Yaml < Puppet::Indirector::Terminus\n  # Read a given name's file in and convert it from YAML.\n  def find(request)\n    file = path(request.key)\n    return nil unless Puppet::FileSystem.exist?(file)\n\n    begin\n      load_file(file)\n    rescue Puppet::Util::Yaml::YamlLoadError => detail\n      raise Puppet::Error, _(\"Could not parse YAML data for %{indirection} %{request}: %{detail}\") % { indirection: indirection.name, request: request.key, detail: detail }, detail.backtrace\n    end\n  end\n\n  # Convert our object to YAML and store it to the disk.\n  def save(request)\n    raise ArgumentError, _(\"You can only save objects that respond to :name\") unless request.instance.respond_to?(:name)\n\n    file = path(request.key)\n\n    basedir = File.dirname(file)\n\n    # This is quite likely a bad idea, since we're not managing ownership or modes.\n    Dir.mkdir(basedir) unless Puppet::FileSystem.exist?(basedir)\n\n    begin\n      Puppet::Util::Yaml.dump(request.instance, file)\n    rescue TypeError => detail\n      Puppet.err _(\"Could not save %{indirection} %{request}: %{detail}\") % { indirection: name, request: request.key, detail: detail }","sourceCodeStart":1,"sourceCodeEnd":34,"githubUrl":"https://github.com/puppetlabs/puppet/blob/e227c27540975c25aa22d533a52424a9d2fc886a/lib/puppet/indirector/yaml.rb#L1-L34","documentation":"The YAML terminus's find() first checks the file exists, then loads it with Puppet::Util::Yaml.safe_load; a Puppet::Util::Yaml::YamlLoadError (Psych syntax errors, unpermitted classes/aliases under safe loading) is re-raised as Puppet::Error with the indirection, key, and detail. The stored YAML for the given key is present but unreadable by the current Psych/safe-load rules.","triggerScenarios":"Calling find on a yaml-backed indirection (default facts/node/report stores) when the .yaml file is truncated, hand-edited, contains aliases, or contains classes not in the permitted list for the running Puppet version (e.g., data serialized by an older Puppet with symbols or date objects now rejected).","commonSituations":"vardir restored from backup with damaged yaml files; version upgrades tightening safe_load permitted classes; operators hand-editing cache/state yaml; disk-full truncating report writes.","solutions":["Read the %{detail}: Psych::SyntaxError points to the line/column; unknown class/alias messages tell you the safe-load rule that fired","Delete or quarantine the damaged file so find() returns nil (ENOENT path) and the object is rebuilt from its source","If the file must be preserved, load it permissively in a separate ruby process, sanitize (drop aliases, stringify symbols), and re-dump","After Puppet upgrades, expect stricter permitted-class lists; pre-convert old serialized data rather than keeping old formats in place"],"exampleFix":"# before\n# Error: Could not parse YAML data for facts web01: Psych::DisallowedClass:\n#        Tried to load unspecified class: Date\n\n# after: sanitize the stored file once, then re-save\nruby -ryaml -e '\n  d = YAML.unsafe_load_file(\"/var/cache/puppet/yaml/facts/web01.yaml\")\n  d.values.each { |k,v| d.values[k] = v.to_s if v.is_a?(Date) }\n  YAML.safe_dump(d, File.open(\"/var/cache/puppet/yaml/facts/web01.yaml\",\"w\"), permitted_classes: [Symbol])\n'\npuppet agent -t","handlingStrategy":"try-catch","validationCode":"file = File.join(base_dir, \"#{key}.yaml\")\nif Puppet::FileSystem.exist?(file)\n  begin\n    Puppet::Util::Yaml.safe_load_file(file)\n  rescue Puppet::Util::Yaml::YamlLoadError => e\n    Puppet.warning \"refusing request: #{file} is not safely loadable: #{e.message}\"\n  end\nend","typeGuard":null,"tryCatchPattern":"begin\n  facts = Puppet::Node::Facts.indirection.find(certname)\nrescue Puppet::Error => e\n  raise unless e.message.start_with?('Could not parse YAML data')\n  File.delete(File.join(dir, \"#{certname}.yaml\")) rescue nil\n  facts = nil  # caller falls back to fresh fact collection\nend","preventionTips":["Never hand-edit yaml files under vardir; regenerate them through Puppet","After Puppet upgrades, proactively re-save or purge serialized state files","Monitor disk space where reports/state are written to avoid truncated files"],"tags":["puppet","yaml","safe-load","indirector","deserialization"],"backgroundTag":"yaml-parse-error","analyzedSha":"e227c27540975c25aa22d533a52424a9d2fc886a","analyzedAt":"2026-08-21T20:49:46.650Z","schemaVersion":2},"datasetVersion":"2026-08-21T23:17:16.201Z"}