puppetlabs/puppet · error · ArgumentError

Could not find a valid module at

Error message

Could not find a valid module at %{path}

What it means

`puppet module changes <path>` (the `changes` action of the module Face) raises ArgumentError when Puppet::ModuleTool.find_module_root(path) returns nil. find_module_root ascends from the given path looking for a directory containing metadata.json; if none exists at or above the path, no module can be located and the tool refuses to check it for modified files.

Solutions

  1. cd into the module root (the directory containing metadata.json) and run `puppet module changes .`
  2. Verify a metadata.json exists: `ls <path>/metadata.json`; if missing, scaffold one with `puppet module generate` or copy from a module template
  3. Double-check the path for typos and confirm it points at a directory, not a single file

Example fix

# before
puppet module changes ~/repos/controlrepo/site/roles
# after
cd ~/repos/controlrepo/site/roles/ntp && puppet module changes .
# (only works once metadata.json exists in that module root)
Defensive patterns

Strategy: validation

Validate before calling

require 'pathname'
def module_root?(path)
  Pathname.new(File.expand_path(path)).ascend.any? { |d| File.file?(File.join(d, 'metadata.json')) }
end
abort 'not a module: no metadata.json at or above this path' unless module_root?(ARGV[0] || Dir.pwd)

Try / catch

begin
  Puppet::Face[:module, :current].changes(path)
rescue ArgumentError => e
  abort "#{e.message} — run from the directory containing metadata.json"
end

Prevention

When it happens

Trigger: `puppet module changes /some/dir` where no metadata.json exists at or above that directory; passing a path to a single .pp file or a typo'd/nonexistent directory; running the command from the environment root instead of inside a module.

Common situations: Running from the wrong working directory; modules created before metadata.json was standard; control-repo role/profile directories that are not packaged modules; path typos.

Related errors


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

Appendix: source

Thrown at lib/puppet/face/module/changes.rb:29

    EOT

    returns _("Array of strings representing paths of modified files.")

    examples <<-EOT
      Show modified files of an installed module:

      $ puppet module changes /etc/puppetlabs/code/modules/vcsrepo/
      warning: 1 files modified
      lib/puppet/provider/vcsrepo.rb
    EOT

    arguments _("<path>")

    when_invoked do |path, options|
      Puppet::ModuleTool.set_option_defaults options
      root_path = Puppet::ModuleTool.find_module_root(path)
      unless root_path
        raise ArgumentError, _("Could not find a valid module at %{path}") % { path: path.inspect }
      end

      Puppet::ModuleTool::Applications::Checksummer.run(root_path, options)
    end

    when_rendering :console do |return_value|
      if return_value.empty?
        Puppet.notice _("No modified files")
      else
        Puppet.warning _("%{count} files modified") % { count: return_value.size }
      end
      return_value.map(&:to_s).join("\n")
    end
  end
end

View on GitHub (pinned to e227c27540)