puppetlabs/puppet · error · Puppet::ModuleTool::Errors::LocalChangesError
Could not %{action} '%{module_name}'; module has had changes
Error message
Could not %{action} '%{module_name}'; module has had changes made locally What it means
Raised by Puppet::ModuleTool::Applications::Uninstaller (class Puppet::ModuleTool::Errors::LocalChangesError) when you uninstall a module whose files no longer match the checksums recorded for the installed release. Before deleting, the uninstaller runs Puppet::ModuleTool::Applications::Checksummer.run(mod.path) and refuses to destroy locally-modified content unless changes are explicitly ignored. The guard is skipped entirely when --force or --ignore-changes is passed, since @ignore_changes = options[:force] || options[:ignore_changes].
Source
Thrown at lib/puppet/module_tool/applications/uninstaller.rb:103
:module_name => @name
end
end
end
def validate_module
mod = @installed.first
unless @ignore_changes
raise _("Either the `--ignore_changes` or `--force` argument must be specified to uninstall modules when running in FIPS mode.") if Puppet.runtime[:facter].value(:fips_enabled)
changes = begin
Puppet::ModuleTool::Applications::Checksummer.run(mod.path)
rescue ArgumentError
[]
end
if mod.has_metadata? && !changes.empty?
raise LocalChangesError,
:action => :uninstall,
:module_name => (mod.forge_name || mod.name).tr('/', '-'),
:requested_version => @options[:version],
:installed_version => mod.version
end
end
if !@options[:force] && !mod.required_by.empty?
raise ModuleIsRequiredError,
:module_name => (mod.forge_name || mod.name).tr('/', '-'),
:required_by => mod.required_by,
:requested_version => @options[:version],
:installed_version => mod.version
end
end
end
end
endView on GitHub (pinned to e227c27540)
Solutions
- Re-run with `puppet module uninstall <name> --force` (or `--ignore-changes` if you only want to skip the checksum check but keep the dependents check)
- If the edits matter, copy the module directory aside first (cp -r) and then uninstall with --force
- Inspect what changed with `puppet module changes <module-dir>` and revert unintended edits, then uninstall without --force
- Restore pristine content by reinstalling the same release (`puppet module install <name> --version <v> --force`) and then uninstall cleanly
Example fix
# before $ puppet module uninstall puppetlabs-stdlib # Error: Could not uninstall 'puppetlabs-stdlib'; module has had changes made locally # after $ puppet module uninstall puppetlabs-stdlib --force
Defensive patterns
Strategy: validation
Validate before calling
require 'puppet/module_tool/applications/checksummer'
mod = env.modules.find { |m| (m.forge_name || m.name).tr('/', '-') == name }
if mod && mod.has_metadata?
changes = begin
Puppet::ModuleTool::Applications::Checksummer.run(mod.path)
rescue ArgumentError
[]
end
abort "refusing: #{changes.length} locally changed files" unless changes.empty? || options[:force] || options[:ignore_changes]
end Try / catch
result = Puppet::ModuleTool::Applications::Uninstaller.run(name, options)
if result[:error] && result[:error][:oneline] =~ /changes made locally/
# decide: keep edits, back up, or retry with force: true
FileUtils.cp_r(mod.path, "#{mod.path}.bak")
retry_with = options.merge(force: true)
end Prevention
- Never edit Forge modules in place — fork them or wrap them in profile modules
- Manage module content with Puppetfile + r10k so uninstall/upgrade happens in version control, not on live trees
- In automation, pass --force or --ignore-changes deliberately and log the Checksummer diff first
- Run `puppet module changes <dir>` before scripted uninstall/upgrade to make drift visible
When it happens
Trigger: Running `puppet module uninstall <author-module>` (or Uninstaller.new(name, options).run) where the target module has a valid metadata.json (has_metadata? true), Checksummer.run(mod.path) returns a non-empty change set, and neither --force/-f nor --ignore-changes/-c is set.
Common situations: A module from the Forge was hotfixed in place to work around a bug; files were touched by an editor, CI, or a sync tool (line-ending/CRLF rewrites on Windows); an older r10k/librarian-puppet checkout left the tree dirty; permissions or ownership changes alter file digests.
Related errors
- Could not %{action} '%{module_name}'; module has had changes
- Could not %{action} '%{module_name}'; module appears in mult
- Could not %{action} '%{module_name}'; module is not installe
- Could not uninstall '%{module_name}'; no installed version m
- Could not uninstall '%{module_name}'; installed modules stil
AI-assisted analysis of puppetlabs/puppet@e227c27540 (2026-08-21).
Data as JSON: /api/errors/4327ec97a6adde57.
Report an issue: GitHub.