puppetlabs/puppet · error · FileReadError

Could not retrieve user %{user}: %{detail}

Error message

Could not retrieve user %{user}: %{detail}

What it means

The :crontab filetype keys its storage off a user, and path= resolves that user with Puppet::Util.uid. When the lookup itself raises Puppet::Error (an unknown user converted by Puppet's POSIX layer, or a failing NSS/LDAP backend), it is wrapped as Puppet::Util::FileType::FileReadError 'Could not retrieve user ...'. This is the error path, not the absent path — a user whose uid simply returns nil is later treated as an empty crontab.

Source

Thrown at lib/puppet/util/filetype.rb:185

  end

  # Handle Linux-style cron tabs.
  #
  # TODO: We can possibly eliminate the "-u <username>" option in cmdbase
  # by just running crontab under <username>'s uid (like we do for suntab
  # and aixtab). It may be worth investigating this alternative
  # implementation in the future. This way, we can refactor all three of
  # our cron file types into a common crontab file type.
  newfiletype(:crontab) do
    def initialize(user)
      self.path = user
    end

    def path=(user)
      begin
        @uid = Puppet::Util.uid(user)
      rescue Puppet::Error => detail
        raise FileReadError, _("Could not retrieve user %{user}: %{detail}") % { user: user, detail: detail }, detail.backtrace
      end

      # XXX We have to have the user name, not the uid, because some
      # systems *cough*linux*cough* require it that way
      @path = user
    end

    # Read a specific @path's cron tab.
    def read
      unless Puppet::Util.uid(@path)
        Puppet.debug _("The %{path} user does not exist. Treating their crontab file as empty in case Puppet creates them in the middle of the run.") % { path: @path }

        return ""
      end

      Puppet::Util::Execution.execute("#{cmdbase} -l", failonfail: true, combine: true)
    rescue => detail
      case detail.to_s

View on GitHub (pinned to e227c27540)

Solutions

  1. Verify the user resolves on the host with getent passwd <user> — this exercises the same NSS path Puppet uses
  2. Ensure the user resource is applied before the cron resource (require/before) or fix the username
  3. Fix the name-service backend (sssd/nsswitch.conf) when getent itself fails
  4. Rescue FileReadError in code that manages crontabs for optional users

Example fix

# before
filetype = Puppet::Util::FileType.filetype(:crontab).new(params[:user])
# 'deploy' has no passwd entry => FileReadError: Could not retrieve user deploy

# after
require 'etc'
user = params[:user]
found = begin
  Etc.getpwnam(user)
rescue ArgumentError
  nil
end
raise ArgumentError, "user #{user} missing" unless found
filetype = Puppet::Util::FileType.filetype(:crontab).new(user)
Defensive patterns

Strategy: validation

Validate before calling

require 'etc'

user = resource[:user]
begin
  Etc.getpwnam(user)
rescue ArgumentError
  raise ArgumentError, "user #{user} not found"
end
Puppet::Util::FileType.filetype(:crontab).new(user)

Try / catch

begin
  ft = Puppet::Util::FileType.filetype(:crontab).new(user)
rescue Puppet::Util::FileType::FileReadError => e
  Puppet.err("skipping crontab for #{user}: #{e.message}")
  nil
end

Prevention

When it happens

Trigger: Puppet::Util::FileType.filetype(:crontab).new('bob') (or a cron resource with user => 'bob') on a host where 'bob' does not exist and the POSIX lookup raises, or where getpwnam goes through NSS/LDAP/SSSD and the backend errors.

Common situations: Cron resources referencing users managed later in the catalog or typo'd; LDAP/SSSD outages or misconfigured nsswitch.conf making user lookups raise; minimal containers without the user database.

Related errors


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