puppetlabs/puppet · error · ArgumentError

Malformed dependency: %{name}. Exception was: %{detail}

Error message

Malformed dependency: %{name}. Exception was: %{detail}

What it means

When Puppet::Forge builds a ModuleRelease from a release's metadata.json, each dependency is run through Puppet::ModuleTool.parse_module_dependency, which validates the name and version_requirement as a semantic-version range. An ArgumentError from that parse is re-raised as 'Malformed dependency' with the dependency name and original exception text, identifying the broken release ('name@version').

Source

Thrown at lib/puppet/forge.rb:140

  end

  class ModuleRelease < SemanticPuppet::Dependency::ModuleRelease
    attr_reader :install_dir, :metadata

    def initialize(source, data)
      @data = data
      @metadata = meta = data['metadata']

      name = meta['name'].tr('/', '-')
      version = SemanticPuppet::Version.parse(meta['version'])
      release = "#{name}@#{version}"

      if meta['dependencies']
        dependencies = meta['dependencies'].collect do |dep|
          Puppet::ModuleTool::Metadata.new.add_dependency(dep['name'], dep['version_requirement'], dep['repository'])
          Puppet::ModuleTool.parse_module_dependency(release, dep)[0..1]
        rescue ArgumentError => e
          raise ArgumentError, _("Malformed dependency: %{name}.") % { name: dep['name'] } +
                               ' ' + _("Exception was: %{detail}") % { detail: e }
        end
      else
        dependencies = []
      end

      super(source, name, version, dependencies.to_h)
    end

    def install(dir)
      staging_dir = prepare

      module_dir = dir + name[/-(.*)/, 1]
      module_dir.rmtree if module_dir.exist?

      # Make sure unpacked module has the same ownership as the folder we are moving it into.
      Puppet::ModuleTool::Applications::Unpacker.harmonize_ownership(dir, staging_dir)

View on GitHub (pinned to e227c27540)

Solutions

  1. Find the offending release from the '<name>@<version>' in the message and fix its metadata.json dependency (name must be 'owner/module', version_requirement must be a valid semver range like '>= 1.0.0 < 3.0.0')
  2. Publish a corrected release of that module and depend on it
  3. If you do not control the module, vendor it locally (fix metadata, install from the local path) or pin to an older release whose metadata is valid
  4. Validate your own modules' metadata.json with `puppet module build`/metadata-lint before publishing

Example fix

// before (metadata.json)
"dependencies": [
  { "name": "puppetlabs/stdlib", "version_requirement": "^9.0.0" }
]

// after
"dependencies": [
  { "name": "puppetlabs/stdlib", "version_requirement": ">= 9.0.0 < 10.0.0" }
]
Defensive patterns

Strategy: try-catch

Validate before calling

# Validate module metadata dependencies before install/publish
require 'semantic_puppet'

def deps_valid?(metadata)
  Array(metadata['dependencies']).all? do |d|
    d['name'].match?(%r{\A[a-zA-Z0-9_-]+/[a-zA-Z0-9_-]+\z}) &&
      begin
        SemanticPuppet::VersionRange.parse(d['version_requirement'].to_s)
        true
      rescue ArgumentError
        false
      end
  end
end

Type guard

def well_formed_dependency?(dep)
  dep.is_a?(Hash) && dep['name'].to_s.match?(%r{\A[\w-]+/[\w-]+\z}) &&
    SemanticPuppet::VersionRange.parse(dep['version_requirement'].to_s)
  true
rescue ArgumentError
  false
end

Try / catch

begin
  Puppet::Forge.new.repository.retrieve_release(...) # or puppet module install via API
rescue ArgumentError => e
  raise unless e.message.start_with?('Malformed dependency')
  # e.message names the dep and the nested parse error; pin an older release or vendor the module
end

Prevention

When it happens

Trigger: `puppet module install` (or puppet agent dependency resolution) fetching a release whose metadata.json contains a dependency with an invalid version_requirement (e.g. 'latest', 'abc', mismatched operators) or a malformed dependency name; building a ModuleRelease object directly from hand-edited metadata.

Common situations: Module authors hand-writing version_requirement strings instead of using `puppet module generate`; metadata.json edited after publishing; transitive dependency published with bad metadata breaks every consumer; version ranges copied from non-semver ecosystems (npm-style '^1.0.0' is invalid here).

Understand the failure class

Related errors


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