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

Could not %{action} '%{module_name}'; module appears in mult

Error message

Could not %{action} '%{module_name}'; module appears in multiple places in the module path

What it means

Raised by the Upgrader as Puppet::ModuleTool::Errors::MultipleInstalledError when more than one installed module matches the requested forge name. The candidate search covers every directory in the modulepath, so two copies of the same module (e.g. one in the environment's modulepath and one in basemodulepath) make the upgrade target ambiguous and Puppet refuses to pick one.

Source

Thrown at lib/puppet/module_tool/applications/upgrader.rb:50

        name = @name.tr('/', '-')
        version = options[:version] || '>= 0.0.0'

        results = {
          :action => :upgrade,
          :requested_version => options[:version] || :latest,
        }

        begin
          all_modules = @environment.modules_by_path.values.flatten
          matching_modules = all_modules.select do |x|
            x.forge_name && x.forge_name.tr('/', '-') == name
          end

          if matching_modules.empty?
            raise NotInstalledError, results.merge(:module_name => name)
          elsif matching_modules.length > 1
            raise MultipleInstalledError, results.merge(:module_name => name, :installed_modules => matching_modules)
          end

          installed_release = installed_modules[name]

          # `priority` is an attribute of a `SemanticPuppet::Dependency::Source`,
          # which is delegated through `ModuleRelease` instances for the sake of
          # comparison (sorting). By default, the `InstalledModules` source has
          # a priority of 10 (making it the most preferable source, so that
          # already installed versions of modules are selected in preference to
          # modules from e.g. the Forge). Since we are specifically looking to
          # upgrade this module, we don't want the installed version of this
          # module to be chosen in preference to those with higher versions.
          #
          # This implementation is suboptimal, and since we can expect this sort
          # of behavior to be reasonably common in Semantic, we should probably
          # see about implementing a `ModuleRelease#override_priority` method
          # (or something similar).
          def installed_release.priority

View on GitHub (pinned to e227c27540)

Solutions

  1. Run `puppet module list --environment <env>` (and check `puppet config print modulepath basemodulepath`) to locate every copy
  2. Remove the stale copy: `puppet module uninstall <name> --environment <env>` or delete the redundant directory manually
  3. Keep exactly one canonical location per environment and let Puppetfile/r10k manage it
  4. Retry `puppet module upgrade <name>` once only one match remains

Example fix

# before
$ puppet module upgrade puppetlabs-stdlib
# Error: ... module appears in multiple places in the module path

# after
$ puppet module list --tree   # shows both copies
$ rm -rf /etc/puppetlabs/code/modules/stdlib   # remove global copy
$ puppet module upgrade puppetlabs-stdlib
Defensive patterns

Strategy: validation

Validate before calling

matches = env.modules_by_path.values.flatten
  .select { |m| m.forge_name && m.forge_name.tr('/', '-') == name }
if matches.length > 1
  abort "multiple copies: #{matches.map(&:modulepath).join(', ')} — remove all but one"
end

Try / catch

result = Puppet::ModuleTool::Applications::Upgrader.new(name, options).run
if result[:error] && result[:error][:oneline] =~ /multiple places/
  matches.each { |m| FileUtils.rm_rf(m.path) }  # or keep the canonical one
  retry
end

Prevention

When it happens

Trigger: Running `puppet module upgrade <author-module>` while a module with the same forge_name exists in two or more modulepath directories (matching_modules.length > 1), e.g. environment 'modules/' plus '/etc/puppetlabs/code/environments/production/modules' and a site-wide path.

Common situations: Module installed both per-environment and globally; a directory copied manually next to a puppet-installed copy; basemodulepath defaults pulling in an extra location; leftover copies after a migration of code to a new environment path.

Related errors


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