{"record":{"id":"e5d6466c3f58fe78","repo":"puppetlabs/puppet","slug":"task-names-must-start-with-a-lowercase-letter-and","errorCode":null,"errorMessage":"Task names must start with a lowercase letter and be composed of only lowercase letters, numbers, and underscores","messagePattern":"Task names must start with a lowercase letter and be composed of only lowercase letters, numbers, and underscores","errorType":"exception","errorClass":"InvalidName","httpStatus":null,"severity":"error","filePath":"lib/puppet/module/task.rb","lineNumber":230,"sourceCode":"    def self.tasks_in_module(pup_module)\n      task_files = Dir.glob(File.join(pup_module.tasks_directory, '*'))\n                      .keep_if { |f| is_tasks_file?(f) }\n\n      module_executables = task_files.reject(&method(:is_tasks_metadata_filename?)).map.to_a\n\n      tasks = task_files.group_by { |f| task_name_from_path(f) }\n\n      tasks.map do |task, executables|\n        new_with_files(pup_module, task, executables, module_executables)\n      end\n    end\n\n    attr_reader :name, :module, :metadata_file\n\n    # file paths must be relative to the modules task directory\n    def initialize(pup_module, task_name, module_executables, metadata_file = nil)\n      unless Puppet::Module::Task.is_task_name?(task_name)\n        raise InvalidName, _(\"Task names must start with a lowercase letter and be composed of only lowercase letters, numbers, and underscores\")\n      end\n\n      name = task_name == \"init\" ? pup_module.name : \"#{pup_module.name}::#{task_name}\"\n\n      @module = pup_module\n      @name = name\n      @metadata_file = metadata_file\n      @module_executables = module_executables || []\n    end\n\n    def self.read_metadata(file)\n      if file\n        content = Puppet::FileSystem.read(file, :encoding => 'utf-8')\n        content.empty? ? {} : Puppet::Util::Json.load(content)\n      end\n    rescue SystemCallError, IOError => err\n      msg = _(\"Error reading metadata: %{message}\" % { message: err.message })\n      raise InvalidMetadata.new(msg, 'puppet.tasks/unreadable-metadata')","sourceCodeStart":212,"sourceCodeEnd":248,"githubUrl":"https://github.com/puppetlabs/puppet/blob/e227c27540975c25aa22d533a52424a9d2fc886a/lib/puppet/module/task.rb#L212-L248","documentation":"Raised by Puppet::Module::Task#initialize when a task name fails Puppet::Module::Task.is_task_name?. Task names become the middle segment of the fully-qualified task name (module::taskname) and must start with a lowercase letter and contain only lowercase letters, digits, and underscores. Names are derived from filenames in the module's tasks/ directory, so an invalid filename makes every task in that module unlistable.","triggerScenarios":"A file in tasks/ such as 'MyTask.sh', '2restart.rb', 'my-task.py', or 'task.name' — the basename before the first extension is passed to is_task_name? when Task.instances or Task.new is constructed; the first bad file raises Puppet::Module::Task::InvalidName and aborts task discovery for the run.","commonSituations":"Copying a bolt plan/script with dashes into tasks/; Windows-origin files with uppercase names; test fixtures or editor swap files (e.g. '#task.rb#') left in tasks/; subdirectories with unsupported names.","solutions":["Rename the offending file(s) in the module's tasks/ directory to /^[a-z][a-z0-9_]*$/ (e.g. 'restart_service.sh' -> 'restart_service.sh' kept, 'Restart-Service.sh' -> 'restart_service.sh').","Delete stray non-task files (backups, swap files, .DS_Store) from tasks/.","If you need word separation, use underscores, never dashes.","Verify with `puppet module tasks list <module>` or `bolt task show`."],"exampleFix":"# before: modules/mymodule/tasks/Restart-Service.py\n\n# after: modules/mymodule/tasks/restart_service.py","handlingStrategy":"validation","validationCode":"task_name = File.basename(file, File.extname(file))\nunless task_name.match?(\\A[a-z][a-z0-9_]*\\z)\n  warn \"skipping invalid task file #{file}\"; next\nend","typeGuard":"def task_name?(str)\n  str.is_a?(String) && str.match?(\\A[a-z][a-z0-9_]*\\z)\nend","tryCatchPattern":"begin\n  Puppet::Module::Task.new_with_files(mod, name, executables)\nrescue Puppet::Module::Task::InvalidName => e\n  warn \"invalid task name #{name}: #{e.message}\"\nend","preventionTips":["Generate tasks with `bolt task new <module> <task>` so naming conventions are followed.","Keep task filenames lowercase snake_case; reject dashes/uppercase in code review.","Exclude editor backup files (#{...}#, *.swp, .DS_Store) from tasks/ via clean checkouts."],"tags":["puppet","tasks","name-validation","filenames"],"backgroundTag":"invalid-identifier-name","analyzedSha":"e227c27540975c25aa22d533a52424a9d2fc886a","analyzedAt":"2026-08-21T20:49:46.650Z","schemaVersion":2},"datasetVersion":"2026-08-21T23:17:16.201Z"}