puppetlabs/puppet · error · Puppet::Error

Could not read password hash file at #

Error message

Could not read password hash file at #{password_hash_file}

What it means

Raised by Puppet's macOS DirectoryService user provider when the OS X 10.5/10.6 password hash file (/var/db/shadow/hash/<GUID>) exists and is a regular file, but File.readable? returns false — the process lacks read permission on it. get_sha1 then refuses to read and raises instead of silently returning nil.

Solutions

  1. Run the Puppet agent as root (macOS password management requires it).
  2. Check and restore expected ownership/permissions: `ls -l /var/db/shadow/hash/` — files are typically 0400 root:wheel.
  3. Verify readability as root: `sudo head -c 4 /var/db/shadow/hash/<GUID>`.
  4. If the hardening change was intentional, exclude these paths or stop managing passwords on those legacy systems.
Defensive patterns

Strategy: validation

Validate before calling

file = '/var/db/shadow/hash/<GUID>'
if File.exist?(file)
  File.readable?(file) or raise 'not readable - run agent as root'
end

Prevention

When it happens

Trigger: Reading/inspecting a 10.5–10.6 user's password hash when the agent runs as a non-root user, or the file's mode/ACL was tightened (these shadow files are normally root-only), or filesystem damage changed ownership.

Common situations: Puppet agent accidentally running as non-root; security hardening scripts that chmod 000 /var/db/shadow/hash/*; migrated volumes with wrong ownership.

Related errors


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

Appendix: source

Thrown at lib/puppet/provider/user/directoryservice.rb:237

      if value.nil?
        raise Puppet::Error, "Invalid #{field} given for user #{user_name}"
      end

      value.unpack1('H*')
    when 'iterations'
      Integer(embedded_binary_plist['SALTED-SHA512-PBKDF2'][field])
    else
      raise Puppet::Error, "Puppet has tried to read an incorrect value from the user #{user_name} in the SALTED-SHA512-PBKDF2 hash. Acceptable fields are 'salt', 'entropy', or 'iterations'."
    end
  end

  # In versions 10.5 and 10.6 of OS X, the password hash is stored in a file
  # in the /var/db/shadow/hash directory that matches the GUID of the user.
  def self.get_sha1(guid)
    password_hash = nil
    password_hash_file = "#{password_hash_dir}/#{guid}"
    if Puppet::FileSystem.exist?(password_hash_file) and File.file?(password_hash_file)
      raise Puppet::Error, "Could not read password hash file at #{password_hash_file}" unless File.readable?(password_hash_file)

      f = File.new(password_hash_file)
      password_hash = f.read
      f.close
    end
    password_hash
  end

  ##                   ##
  ## Ensurable Methods ##
  ##                   ##

  def exists?
    begin
      dscl '.', 'read', "/Users/#{@resource.name}"
    rescue Puppet::ExecutionFailure => e
      Puppet.debug("User was not found, dscl returned: #{e.inspect}")
      return false

View on GitHub (pinned to e227c27540)