puppetlabs/puppet · error · Puppet::Module::Task::InvalidMetadata

puppet.tasks/invalid-metadata

puppet.tasks/invalid-metadata

Error message

The 'files' task metadata expects an array, got %{files}.

What it means

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}.

Source

Thrown at lib/puppet/module/task.rb:94

    def self.get_file_details(path, mod)
      # This gets the path from the starting point onward
      # For files this should be the file subpath from the metadata
      # For directories it should be the directory subpath plus whatever we globbed
      # Partition matches on the first instance it finds of the parameter
      name = "#{mod.name}#{path.partition(mod.path).last}"

      { "name" => name, "path" => path }
    end
    private_class_method :get_file_details

    # Find task's required lib files and retrieve paths for both 'files' and 'implementation:files' metadata keys
    def self.find_extra_files(metadata, envname = nil)
      return [] if metadata.nil?

      files = metadata.fetch('files', [])
      unless files.is_a?(Array)
        msg = _("The 'files' task metadata expects an array, got %{files}.") % { files: files }
        raise InvalidMetadata.new(msg, 'puppet.tasks/invalid-metadata')
      end
      impl_files = metadata.fetch('implementations', []).flat_map do |impl|
        file_array = impl.fetch('files', [])
        unless file_array.is_a?(Array)
          msg = _("The 'files' task metadata expects an array, got %{files}.") % { files: file_array }
          raise InvalidMetadata.new(msg, 'puppet.tasks/invalid-metadata')
        end
        file_array
      end

      combined_files = files + impl_files
      combined_files.uniq.flat_map do |file|
        module_name, mount, endpath = file.split("/", 3)
        # If there's a mount directory with no trailing slash this will be nil
        # We want it to be empty to construct a path
        endpath ||= ''

        pup_module = Puppet::Module.find(module_name, envname)

View on GitHub (pinned to e227c27540)

Solutions

  1. Reproduce manually: `sudo -u <puppetuser> crontab -r` (with the same -u semantics) and read the underlying message
  2. Remove the stale spool entry under /var/spool/cron/crontabs if its user no longer exists
  3. Run the agent as root, and verify `lssrc -s cron` shows active
  4. Install bos.acct if crontab is missing
Defensive patterns

Strategy: try-catch

Try / catch

begin
  filetype.remove
rescue Puppet::Util::FileType::FileReadError => e
  raise unless e.message =~ /open.*in.*directory|not.*authorized.*cron/
  # spool already absent / denied -> treat as removed
end

Prevention

When it happens

Trigger: 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.

Common situations: Removing cron jobs during service decommissioning; stale /var/spool/cron/crontabs entries after account deletion; hardened AIX builds without cron filesets.

Related errors


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