{"record":{"id":"7071fd1450961d01","repo":"puppetlabs/puppet","slug":"malformed-dependency-name-exception-was-de","errorCode":null,"errorMessage":"Malformed dependency: %{name}. Exception was: %{detail}","messagePattern":"Malformed dependency: %(.+?)\\. Exception was: %(.+?)","errorType":"exception","errorClass":"ArgumentError","httpStatus":null,"severity":"error","filePath":"lib/puppet/forge.rb","lineNumber":140,"sourceCode":"  end\n\n  class ModuleRelease < SemanticPuppet::Dependency::ModuleRelease\n    attr_reader :install_dir, :metadata\n\n    def initialize(source, data)\n      @data = data\n      @metadata = meta = data['metadata']\n\n      name = meta['name'].tr('/', '-')\n      version = SemanticPuppet::Version.parse(meta['version'])\n      release = \"#{name}@#{version}\"\n\n      if meta['dependencies']\n        dependencies = meta['dependencies'].collect do |dep|\n          Puppet::ModuleTool::Metadata.new.add_dependency(dep['name'], dep['version_requirement'], dep['repository'])\n          Puppet::ModuleTool.parse_module_dependency(release, dep)[0..1]\n        rescue ArgumentError => e\n          raise ArgumentError, _(\"Malformed dependency: %{name}.\") % { name: dep['name'] } +\n                               ' ' + _(\"Exception was: %{detail}\") % { detail: e }\n        end\n      else\n        dependencies = []\n      end\n\n      super(source, name, version, dependencies.to_h)\n    end\n\n    def install(dir)\n      staging_dir = prepare\n\n      module_dir = dir + name[/-(.*)/, 1]\n      module_dir.rmtree if module_dir.exist?\n\n      # Make sure unpacked module has the same ownership as the folder we are moving it into.\n      Puppet::ModuleTool::Applications::Unpacker.harmonize_ownership(dir, staging_dir)\n","sourceCodeStart":122,"sourceCodeEnd":158,"githubUrl":"https://github.com/puppetlabs/puppet/blob/e227c27540975c25aa22d533a52424a9d2fc886a/lib/puppet/forge.rb#L122-L158","documentation":"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').","triggerScenarios":"`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.","commonSituations":"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).","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"],"exampleFix":"// before (metadata.json)\n\"dependencies\": [\n  { \"name\": \"puppetlabs/stdlib\", \"version_requirement\": \"^9.0.0\" }\n]\n\n// after\n\"dependencies\": [\n  { \"name\": \"puppetlabs/stdlib\", \"version_requirement\": \">= 9.0.0 < 10.0.0\" }\n]","handlingStrategy":"try-catch","validationCode":"# Validate module metadata dependencies before install/publish\nrequire 'semantic_puppet'\n\ndef deps_valid?(metadata)\n  Array(metadata['dependencies']).all? do |d|\n    d['name'].match?(%r{\\A[a-zA-Z0-9_-]+/[a-zA-Z0-9_-]+\\z}) &&\n      begin\n        SemanticPuppet::VersionRange.parse(d['version_requirement'].to_s)\n        true\n      rescue ArgumentError\n        false\n      end\n  end\nend","typeGuard":"def well_formed_dependency?(dep)\n  dep.is_a?(Hash) && dep['name'].to_s.match?(%r{\\A[\\w-]+/[\\w-]+\\z}) &&\n    SemanticPuppet::VersionRange.parse(dep['version_requirement'].to_s)\n  true\nrescue ArgumentError\n  false\nend","tryCatchPattern":"begin\n  Puppet::Forge.new.repository.retrieve_release(...) # or puppet module install via API\nrescue ArgumentError => e\n  raise unless e.message.start_with?('Malformed dependency')\n  # e.message names the dep and the nested parse error; pin an older release or vendor the module\nend","preventionTips":["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"],"tags":["puppet","forge","module-metadata","dependency-resolution","argumenterror"],"backgroundTag":"invalid-module-metadata","analyzedSha":"e227c27540975c25aa22d533a52424a9d2fc886a","analyzedAt":"2026-08-21T20:49:46.650Z","schemaVersion":2},"datasetVersion":"2026-08-21T23:17:16.201Z"}