puppetlabs/puppet · error · Puppet::ModuleTool::Errors::InvalidModuleError

Could not %{action} '%{module_name}'; %{error}

Error message

Could not %{action} '%{module_name}'; %{error}

What it means

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.

Source

Thrown at lib/puppet/module_tool/applications/installer.rb:258

          }
        ensure
          results[:result] ||= :failure
        end

        results
      end

      private

      def module_repository
        @repo ||= Puppet::Forge.new(Puppet[:module_repository])
      end

      def local_tarball_source
        @tarball_source ||= begin
          Puppet::ModuleTool::LocalTarball.new(@name)
        rescue Puppet::Module::Error => e
          raise InvalidModuleError.new(@name, :action => @action, :error => e)
        end
      end

      def installed_modules_source
        @installed ||= Puppet::ModuleTool::InstalledModules.new(@environment)
      end

      def installed_modules
        installed_modules_source.modules
      end

      def build_single_module_graph(name, version)
        range = Puppet::Module.parse_range(version)
        graph = SemanticPuppet::Dependency::Graph.new(name => range)
        releases = SemanticPuppet::Dependency.fetch_releases(name)
        releases.each { |release| release.dependencies.clear }
        graph << releases
      end

View on GitHub (pinned to e227c27540)

Solutions

  1. Build the package with `puppet module build ./my-module` and install the resulting ./pkg/*.tar.gz
  2. Inspect the tarball: `tar tzf foo.tar.gz | head` — metadata.json must sit directly under the module root directory
  3. Validate JSON: `ruby -rjson -e 'puts JSON.parse(File.read("metadata.json"))'` and fix syntax errors
  4. Ensure metadata.json contains required fields (name, version, source) and the name matches owner-module with a hyphen

Example fix

# before
# tarball built by zipping the parent directory, metadata.json buried one level too deep
puppet module install ./foo.tar.gz
# after
cd my-module && puppet module build .
puppet module install ./pkg/my-module-0.1.0.tar.gz
Defensive patterns

Strategy: try-catch

Validate before calling

# Verify a tarball is a well-formed module package before installing
require 'json'
require 'rubygems/package'
Gem::Package::TarReader.new(Zlib::GzipReader.open('foo.tar.gz')) do |tar|
  entry = tar.find { |t| t.full_name.end_with?('metadata.json') }
  raise 'no metadata.json at module root' unless entry
  JSON.parse(entry.read)
end

Try / catch

begin
  Puppet::ModuleTool::Applications::Installer.run('./foo.tar.gz', options)
rescue Puppet::ModuleTool::Errors::InvalidModuleError => e
  # e.message embeds the underlying Puppet::Module::Error (usually a metadata.json parse failure)
  puts e.multiline
  raise
end

Prevention

When it happens

Trigger: `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.

Common situations: 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.

Related errors


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