puppetlabs/puppet · error · ArgumentError

Could not find a valid module at %{path}

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.

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)

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.