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.priorityView on GitHub (pinned to e227c27540)
Solutions
- Run `puppet module list --environment <env>` (and check `puppet config print modulepath basemodulepath`) to locate every copy
- Remove the stale copy: `puppet module uninstall <name> --environment <env>` or delete the redundant directory manually
- Keep exactly one canonical location per environment and let Puppetfile/r10k manage it
- 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
- Keep one module location per environment and let r10k own it; avoid mixing basemodulepath installs with environment installs
- After environment migrations, sweep for leftover module directories with the same short name
- Audit modulepath (`puppet config print modulepath basemodulepath`) in CI so extra paths fail loudly
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
- Could not %{action} '%{module_name}'; module is not installe
- '%{module_name}' (%{version}) requested; installation confli
- '%{module_name}' (%{version}) requested; installation confli
- Could not %{action} '%{module_name}'; module appears in mult
- Could not %{action} '%{module_name}'; module has had changes
AI-assisted analysis of puppetlabs/puppet@e227c27540 (2026-08-21).
Data as JSON: /api/errors/e1f4538d584897c3.
Report an issue: GitHub.