puppetlabs/puppet · error · Puppet::DataBinding::LookupError

Unable to parse %{message}

Error message

Unable to parse %{message}

What it means

While resolving Hiera data through the 'yaml_data' function, Puppet::Util::Yaml.safe_load raised a YamlLoadError (unparsable YAML, forbidden alias, or a disallowed Ruby object/tag). The function rescues it and re-raises as Puppet::DataBinding::LookupError prefixed 'Unable to parse', aborting the catalog compile. Unlike the not-a-hash case, this raises regardless of strict mode.

Source

Thrown at lib/puppet/functions/yaml_data.rb:38

    param 'Puppet::LookupContext', :context
  end

  def yaml_data(options, context)
    path = options['path']
    context.cached_file_data(path) do |content|
      data = Puppet::Util::Yaml.safe_load(content, [Symbol], path)
      if data.is_a?(Hash)
        Puppet::Pops::Lookup::HieraConfig.symkeys_to_string(data)
      else
        msg = _("%{path}: file does not contain a valid yaml hash" % { path: path })
        raise Puppet::DataBinding::LookupError, msg if Puppet[:strict] == :error && data != false

        Puppet.warning(msg)
        {}
      end
    rescue Puppet::Util::Yaml::YamlLoadError => ex
      # YamlLoadErrors include the absolute path to the file, so no need to add that
      raise Puppet::DataBinding::LookupError, _("Unable to parse %{message}") % { message: ex.message }
    end
  end

  def missing_path(options, context)
    "one of 'path', 'paths' 'glob', 'globs' or 'mapped_paths' must be declared in hiera.yaml when using this data_hash function"
  end
end

View on GitHub (pinned to e227c27540)

Solutions

  1. Reproduce the parse locally: ruby -ryaml -e "YAML.safe_load(File.read('file.yaml'), aliases: false)" — the YamlLoadError message embedded in 'Unable to parse %' includes the file and line.
  2. Remove YAML anchors and aliases; inline the repeated values.
  3. Replace tabs with spaces and fix indentation/quote errors reported at the given line.
  4. Use 'puppet lookup --explain' to confirm which matched path is the culprit when globs are involved.

Example fix

# before (safe_load rejects aliases)
base: &base
  server: 'puppet.example.com'
prod:
  <<: *base

# after (inline the data)
base:
  server: 'puppet.example.com'
prod:
  server: 'puppet.example.com'
Defensive patterns

Strategy: validation

Validate before calling

require 'yaml'

def parseable?(path)
  YAML.safe_load(File.read(path), permitted_classes: [Symbol], aliases: false)
  true
rescue Psych::SyntaxError, StandardError => e
  warn "#{path}: #{e.message}"
  false
end

exit 1 unless Dir['data/**/*.yaml'].all? { |f| parseable?(f) }

Try / catch

begin
  value = Puppet.lookup(:hiera).lookup(key, scope)
rescue Puppet::DataBinding::LookupError => e
  # e.message starts with 'Unable to parse' and includes file/line
  raise if ENV['STRICT_HIERA']
  default_value
end

Prevention

When it happens

Trigger: A matched YAML file contains anchors/aliases (&base / *ref), which safe_load rejects; tab characters used for indentation; unbalanced quotes or brackets; binary or corrupted file content; a wrong file pulled in by a glob or mapped_paths entry.

Common situations: Trying to DRY hiera files with YAML anchors (works in some external tools, rejected by safe_load); copy-pasting rendered ERB/EPP output that introduces tabs; a file truncated mid-deploy; symlinking non-hiera YAML into the datadir.

Understand the failure class

Related errors


AI-assisted analysis of puppetlabs/puppet@e227c27540 (2026-08-21). Data as JSON: /api/errors/fa89536d39f31c12. Report an issue: GitHub.