{"record":{"id":"e1b4f64db1f5ca20","repo":"puppetlabs/puppet","slug":"puppet-tasks-invalid-metadata","errorCode":"puppet.tasks/invalid-metadata","errorMessage":"The 'files' task metadata expects an array, got %{files}.","messagePattern":"The 'files' task metadata expects an array, got %(.+?)\\.","errorType":"validation","errorClass":"Puppet::Module::Task::InvalidMetadata","httpStatus":null,"severity":"error","filePath":"lib/puppet/module/task.rb","lineNumber":94,"sourceCode":"    def self.get_file_details(path, mod)\n      # This gets the path from the starting point onward\n      # For files this should be the file subpath from the metadata\n      # For directories it should be the directory subpath plus whatever we globbed\n      # Partition matches on the first instance it finds of the parameter\n      name = \"#{mod.name}#{path.partition(mod.path).last}\"\n\n      { \"name\" => name, \"path\" => path }\n    end\n    private_class_method :get_file_details\n\n    # Find task's required lib files and retrieve paths for both 'files' and 'implementation:files' metadata keys\n    def self.find_extra_files(metadata, envname = nil)\n      return [] if metadata.nil?\n\n      files = metadata.fetch('files', [])\n      unless files.is_a?(Array)\n        msg = _(\"The 'files' task metadata expects an array, got %{files}.\") % { files: files }\n        raise InvalidMetadata.new(msg, 'puppet.tasks/invalid-metadata')\n      end\n      impl_files = metadata.fetch('implementations', []).flat_map do |impl|\n        file_array = impl.fetch('files', [])\n        unless file_array.is_a?(Array)\n          msg = _(\"The 'files' task metadata expects an array, got %{files}.\") % { files: file_array }\n          raise InvalidMetadata.new(msg, 'puppet.tasks/invalid-metadata')\n        end\n        file_array\n      end\n\n      combined_files = files + impl_files\n      combined_files.uniq.flat_map do |file|\n        module_name, mount, endpath = file.split(\"/\", 3)\n        # If there's a mount directory with no trailing slash this will be nil\n        # We want it to be empty to construct a path\n        endpath ||= ''\n\n        pup_module = Puppet::Module.find(module_name, envname)","sourceCodeStart":76,"sourceCodeEnd":112,"githubUrl":"https://github.com/puppetlabs/puppet/blob/e227c27540975c25aa22d533a52424a9d2fc886a/lib/puppet/module/task.rb#L76-L112","documentation":"Raised as Puppet::Util::FileType::FileReadError when the :aixtab remove executes `crontab -r` on AIX and it exits nonzero. Puppet triggers remove when all of a user's crontab entries must go away; the rescue has no tolerated cases, so any crontab failure (permissions, missing user, missing binary, broken cron subsystem) surfaces here with %{detail}.","triggerScenarios":"Purging or ensuring-absent a user's crontab on AIX while the crontab command fails: agent not root, target user deleted leaving a stale spool, bos.acct not installed, or cron src subsystem stopped.","commonSituations":"Removing cron jobs during service decommissioning; stale /var/spool/cron/crontabs entries after account deletion; hardened AIX builds without cron filesets.","solutions":["Reproduce manually: `sudo -u <puppetuser> crontab -r` (with the same -u semantics) and read the underlying message","Remove the stale spool entry under /var/spool/cron/crontabs if its user no longer exists","Run the agent as root, and verify `lssrc -s cron` shows active","Install bos.acct if crontab is missing"],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"begin\n  filetype.remove\nrescue Puppet::Util::FileType::FileReadError => e\n  raise unless e.message =~ /open.*in.*directory|not.*authorized.*cron/\n  # spool already absent / denied -> treat as removed\nend","preventionTips":["Delete a user's cron resources together with the User resource","Prune stale spool files in /var/spool/cron when accounts are removed","Verify cron subsystem health on AIX nodes periodically"],"tags":["puppet","cron","crontab","aix","remove","command-execution"],"backgroundTag":"crontab-command-failed","analyzedSha":"e227c27540975c25aa22d533a52424a9d2fc886a","analyzedAt":"2026-08-21T20:49:46.650Z","schemaVersion":2},"datasetVersion":"2026-08-21T23:17:16.201Z"}