{"record":{"id":"7553f0ecc3e8c567","repo":"puppetlabs/puppet","slug":"could-not-action-module-name-error","errorCode":null,"errorMessage":"Could not %{action} '%{module_name}'; %{error}","messagePattern":"Could not %(.+?) '%(.+?)'; %(.+?)","errorType":"exception","errorClass":"Puppet::ModuleTool::Errors::InvalidModuleError","httpStatus":null,"severity":"error","filePath":"lib/puppet/module_tool/applications/installer.rb","lineNumber":258,"sourceCode":"          }\n        ensure\n          results[:result] ||= :failure\n        end\n\n        results\n      end\n\n      private\n\n      def module_repository\n        @repo ||= Puppet::Forge.new(Puppet[:module_repository])\n      end\n\n      def local_tarball_source\n        @tarball_source ||= begin\n          Puppet::ModuleTool::LocalTarball.new(@name)\n        rescue Puppet::Module::Error => e\n          raise InvalidModuleError.new(@name, :action => @action, :error => e)\n        end\n      end\n\n      def installed_modules_source\n        @installed ||= Puppet::ModuleTool::InstalledModules.new(@environment)\n      end\n\n      def installed_modules\n        installed_modules_source.modules\n      end\n\n      def build_single_module_graph(name, version)\n        range = Puppet::Module.parse_range(version)\n        graph = SemanticPuppet::Dependency::Graph.new(name => range)\n        releases = SemanticPuppet::Dependency.fetch_releases(name)\n        releases.each { |release| release.dependencies.clear }\n        graph << releases\n      end","sourceCodeStart":240,"sourceCodeEnd":276,"githubUrl":"https://github.com/puppetlabs/puppet/blob/e227c27540975c25aa22d533a52424a9d2fc886a/lib/puppet/module_tool/applications/installer.rb#L240-L276","documentation":"Raised when Puppet::ModuleTool::LocalTarball (a SemanticPuppet dependency source that reads a local .tar.gz module package) fails while loading the tarball and raises a Puppet::Module::Error; the installer rescues it in `local_tarball_source` and re-raises it as InvalidModuleError (lib/puppet/module_tool/errors/shared.rb:212). The nested %{error} is the original message, almost always a failure to find or parse metadata.json inside the tarball. It means the file you passed looks like a module package but its metadata is missing, malformed, or not valid JSON with the required fields.","triggerScenarios":"`puppet module install ./foo.tar.gz` where the archive lacks metadata.json, has a syntax error in it (trailing commas, comments), or metadata.json is at the wrong nesting level (not at the root of the module directory inside the tarball). In code: Installer.run('./foo.tar.gz', ...) where Puppet::ModuleTool::LocalTarball.new raises Puppet::Module::Error during unpack/parse.","commonSituations":"Hand-rolled tarballs built with `tar czf` from the wrong directory (metadata.json ends up under an extra path component); editing metadata.json and introducing invalid JSON; tarring the module's parent folder instead of the module folder; a truncated download or a GitHub 'Download ZIP' artifact used in place of a `puppet module build` package.","solutions":["Build the package with `puppet module build ./my-module` and install the resulting ./pkg/*.tar.gz","Inspect the tarball: `tar tzf foo.tar.gz | head` — metadata.json must sit directly under the module root directory","Validate JSON: `ruby -rjson -e 'puts JSON.parse(File.read(\"metadata.json\"))'` and fix syntax errors","Ensure metadata.json contains required fields (name, version, source) and the name matches owner-module with a hyphen"],"exampleFix":"# before\n# tarball built by zipping the parent directory, metadata.json buried one level too deep\npuppet module install ./foo.tar.gz\n# after\ncd my-module && puppet module build .\npuppet module install ./pkg/my-module-0.1.0.tar.gz","handlingStrategy":"try-catch","validationCode":"# Verify a tarball is a well-formed module package before installing\nrequire 'json'\nrequire 'rubygems/package'\nGem::Package::TarReader.new(Zlib::GzipReader.open('foo.tar.gz')) do |tar|\n  entry = tar.find { |t| t.full_name.end_with?('metadata.json') }\n  raise 'no metadata.json at module root' unless entry\n  JSON.parse(entry.read)\nend","typeGuard":null,"tryCatchPattern":"begin\n  Puppet::ModuleTool::Applications::Installer.run('./foo.tar.gz', options)\nrescue Puppet::ModuleTool::Errors::InvalidModuleError => e\n  # e.message embeds the underlying Puppet::Module::Error (usually a metadata.json parse failure)\n  puts e.multiline\n  raise\nend","preventionTips":["Produce packages with `puppet module build`, never ad-hoc tar/czip of the source tree","After editing metadata.json, run a JSON parse check before packaging","Confirm `tar tzf pkg.tar.gz` shows metadata.json directly under the module directory"],"tags":["puppet","module-tool","tarball","metadata-json","installer"],"backgroundTag":"invalid-module-metadata","analyzedSha":"e227c27540975c25aa22d533a52424a9d2fc886a","analyzedAt":"2026-08-21T20:49:46.650Z","schemaVersion":2},"datasetVersion":"2026-08-21T23:17:16.201Z"}