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
- 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')
- Publish a corrected release of that module and depend on it
- 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
- 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
- Generate metadata.json with puppet module generate; never hand-edit version ranges
- Use Puppet semver range syntax (>= x.y.z < a.b.c), not npm/caret syntax
- Run metadata linting in CI for every module you publish
- When a third-party module breaks, pin its previous release in Puppetfile while reporting upstream
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
- Parsing and encoding errors: unexpected token, malformed input — why parsers reject input and how to find the real culprit.
Related errors
- Could not %{action} '%{module_name}', did you mean '%{sugges
- Invalid entry at %{error_location}: '%{file_text}'
- %{mount} is already mounted at %{name} at %{error_location}
- Fileset paths must be fully qualified: %{path}
- Fileset paths must exist
AI-assisted analysis of puppetlabs/puppet@e227c27540 (2026-08-21).
Data as JSON: /api/errors/7071fd1450961d01.
Report an issue: GitHub.