{"record":{"id":"a5b89f0f9aae5f4e","repo":"puppetlabs/puppet","slug":"could-not-action-module-name-did-you-mean","errorCode":null,"errorMessage":"Could not %{action} '%{module_name}', did you mean '%{suggestion}'?","messagePattern":"Could not %(.+?) '%(.+?)', did you mean '%(.+?)'\\?","errorType":"validation","errorClass":"Puppet::ModuleTool::Errors::InvalidModuleNameError","httpStatus":null,"severity":"error","filePath":"lib/puppet/module_tool/applications/installer.rb","lineNumber":64,"sourceCode":"            SemanticPuppet::Dependency.add_source(installed_modules_source)\n            SemanticPuppet::Dependency.add_source(module_repository)\n          end\n\n        else\n          SemanticPuppet::Dependency.add_source(installed_modules_source) unless forced?\n          SemanticPuppet::Dependency.add_source(module_repository)\n        end\n      end\n\n      def run\n        name = @name.tr('/', '-')\n        version = options[:version] || '>= 0.0.0'\n\n        results = { :action => :install, :module_name => name, :module_version => version }\n\n        begin\n          if !@local_tarball && name !~ /-/\n            raise InvalidModuleNameError.new(module_name: @name, suggestion: \"puppetlabs-#{@name}\", action: :install)\n          end\n\n          installed_module = installed_modules[name]\n          if installed_module\n            unless forced?\n              if Puppet::Module.parse_range(version).include? installed_module.version\n                results[:result] = :noop\n                results[:version] = installed_module.version\n                return results\n              else\n                changes = begin\n                  Checksummer.run(installed_modules[name].mod.path)\n                rescue\n                  []\n                end\n                raise AlreadyInstalledError,\n                      :module_name => name,\n                      :installed_version => installed_modules[name].version,","sourceCodeStart":46,"sourceCodeEnd":82,"githubUrl":"https://github.com/puppetlabs/puppet/blob/e227c27540975c25aa22d533a52424a9d2fc886a/lib/puppet/module_tool/applications/installer.rb#L46-L82","documentation":"Raised by Puppet::ModuleTool::Installer#run (wrapped as InvalidModuleNameError in lib/puppet/module_tool/errors/shared.rb:131) when `puppet module install` is given a Forge module name that contains no hyphen and the argument is not a path to a local tarball. Forge module names must be namespaced as `<owner>-<module>` (e.g. puppetlabs-apache), because the hyphen separates the Forge username from the module name. The error includes a suggestion built by prefixing the short name with the most common owner (\"puppetlabs-<name>\").","triggerScenarios":"Running `puppet module install apache` (single word, no slash-to-hyphen translation produces a hyphen-less name). Specifically: `!@local_tarball && name !~ /-/` in installer.rb — i.e. the argument is not an existing tarball file path AND `name.tr('/', '-')` still contains no '-'. Also triggered by the Puppet code API Puppet::ModuleTool::Applications::Installer.run('apache', ...) with the same shape.","commonSituations":"New users installing from the Forge by short name (`puppet module install stdlib` instead of `puppetlabs-stdlib`); shell scripts that pass $MODULE without the owner prefix; typos where the dash is omitted; automation that fetches module names from a list that stores only the short name.","solutions":["Use the fully-qualified Forge name shown in the suggestion: `puppet module install puppetlabs-apache`","If you meant a specific owner, prefix that owner: `puppet module install <owner>-<name>` (e.g. puppet-nginx)","If installing a local package, pass the tarball path instead: `puppet module install ./pkg/apache-9.0.0.tar.gz`","In code, validate the name with /\\A[a-z0-9]+-[a-z0-9_]+\\z/ before calling the installer"],"exampleFix":"# before\npuppet module install apache\n# after\npuppet module install puppetlabs-apache","handlingStrategy":"validation","validationCode":"# Ruby: validate a Forge module name before invoking the installer\nname = 'apache'\nunless name.match?(%r{\\A[a-z0-9][a-z0-9_-]*/[a-z0-9_]+\\z}) || name.match?(%r{\\A[a-z0-9]+-[a-z0-9_]+\\z}) || File.exist?(name)\n  raise ArgumentError, \"#{name} lacks the required owner- prefix; did you mean puppetlabs-#{name}?\"\nend","typeGuard":null,"tryCatchPattern":"begin\n  Puppet::ModuleTool::Applications::Installer.run(name, options)\nrescue Puppet::ModuleTool::Errors::InvalidModuleNameError => e\n  # e.multiline prints the suggested fully-qualified command\n  puts e.multiline\n  raise\nend","preventionTips":["Always install Forge modules with the owner prefix: puppet module install puppetlabs-<name>","In scripts, source names from `puppet module search` output, which is always fully qualified","Treat a missing hyphen in a module name as a lint error in CI"],"tags":["puppet","module-tool","forge","module-name","installer"],"backgroundTag":"invalid-module-name","analyzedSha":"e227c27540975c25aa22d533a52424a9d2fc886a","analyzedAt":"2026-08-21T20:49:46.650Z","schemaVersion":2},"datasetVersion":"2026-08-21T23:17:16.201Z"}