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_sView on GitHub (pinned to e227c27540)
Solutions
- Verify the user resolves on the host with getent passwd <user> — this exercises the same NSS path Puppet uses
- Ensure the user resource is applied before the cron resource (require/before) or fix the username
- Fix the name-service backend (sssd/nsswitch.conf) when getent itself fails
- 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
- Order user creation before cron resources that reference the user
- Check user resolution with getent passwd or Etc.getpwnam before constructing a crontab filetype
- Monitor NSS/SSSD health on nodes that manage per-user crontabs
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
- puppet.tasks/invalid-metadata
- %{klass} could not read %{path}: %{detail}
- %{klass} could not write %{path}: %{detail}
- Path is nil
- No such group %{group}
AI-assisted analysis of puppetlabs/puppet@e227c27540 (2026-08-21).
Data as JSON: /api/errors/5502e7a0786c001b.
Report an issue: GitHub.