puppetlabs/puppet · error · FaultyMetadata

%{name} has an invalid and unparsable metadata.json file. Th

Error message

%{name} has an invalid and unparsable metadata.json file. The parse error: %{error}

What it means

Puppet::Module's metadata reader parses a module's metadata.json with Puppet::Util::Json and, on ParseError, reports 'invalid and unparsable metadata.json' with the underlying parser message (lib/puppet/module.rb:238). What happens next depends on the `strict` setting: :off logs to debug, :warning emits a warning, :error raises Puppet::Module::FaultyMetadata. The same broken file is therefore either noise or a hard failure purely by configuration.

Source

Thrown at lib/puppet/module.rb:238

  def read_metadata
    md_file = metadata_file
    return {} if md_file.nil?

    content = File.read(md_file, :encoding => 'utf-8')
    content.empty? ? {} : Puppet::Util::Json.load(content)
  rescue Errno::ENOENT
    {}
  rescue Puppet::Util::Json::ParseError => e
    # TRANSLATORS 'metadata.json' is a specific file name and should not be translated.
    msg = _("%{name} has an invalid and unparsable metadata.json file. The parse error: %{error}") % { name: name, error: e.message }
    case Puppet[:strict]
    when :off
      Puppet.debug(msg)
    when :warning
      Puppet.warning(msg)
    when :error
      raise FaultyMetadata, msg
    end
    {}
  end

  def load_metadata
    return if instance_variable_defined?(:@metadata)

    @metadata = data = read_metadata
    return if data.empty?

    @forge_name = data['name'].tr('-', '/') if data['name']

    [:source, :author, :version, :license, :dependencies].each do |attr|
      value = data[attr.to_s]
      raise MissingMetadata, "No #{attr} module metadata provided for #{name}" if value.nil?

      if attr == :dependencies
        unless value.is_a?(Array)

View on GitHub (pinned to e227c27540)

Solutions

  1. Validate and repair the JSON: `ruby -rjson -e 'JSON.parse(File.read("metadata.json"))'` or any JSON linter — the parser message in the error pinpoints the offset
  2. Regenerate metadata.json with pdk or `puppet module generate`, which emits valid JSON
  3. If third-party modules must be tolerated despite bad metadata, set `strict = warning` instead of :error — but fixing the file is the real remedy

Example fix

// before (metadata.json)
{
  "name": "acme-web",
  "version": "1.0.0",
  "license": "Apache-2.0",
  "dependencies": [],
}

// after
{
  "name": "acme-web",
  "version": "1.0.0",
  "license": "Apache-2.0",
  "dependencies": []
}
Defensive patterns

Strategy: try-catch

Validate before calling

def valid_module_metadata?(dir)
  path = File.join(dir, 'metadata.json')
  return true unless File.exist?(path)
  Puppet::Util::Json.load(File.read(path))
  true
rescue Puppet::Util::Json::ParseError, Errno::ENOENT
  false
end

Try / catch

begin
  mod = Puppet::Module.find(name, environment)
  mod.load_metadata if mod
rescue Puppet::Module::FaultyMetadata => e
  Puppet.warning("skipping module #{name}: #{e.message}")
  next
end

Prevention

When it happens

Trigger: metadata.json with a trailing comma, comment, single-quoted strings, or BOM; a truncated file from an interrupted module install; running with `strict = error` in puppet.conf while any installed module has malformed metadata.

Common situations: Hand-edited metadata.json; modules generated by non-Puppet tooling; CI enforcing strict=error; files saved as UTF-16.

Understand the failure class

Related errors


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