puppetlabs/puppet · error · Puppet::Error

Invalid #{field} given for user #{user_name}

Error message

Invalid #{field} given for user #{user_name}

What it means

Raised by Puppet's macOS DirectoryService user provider when reading a user's ShadowHashData yields a nil 'salt' or 'entropy' value inside the SALTED-SHA512-PBKDF2 dictionary. get_salted_sha512_pbkdf2 expects both binary keys to exist; a missing key means the stored password hash record is malformed or of a different format.

Source

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

    Puppet::Util::Plist.parse_plist(plist_data)
  end

  # The salted-SHA512 password hash in 10.7 is stored in the 'SALTED-SHA512'
  # key as binary data. That data is extracted and converted to a hex string.
  def self.get_salted_sha512(embedded_binary_plist)
    embedded_binary_plist['SALTED-SHA512'].unpack1("H*")
  end

  # This method reads the passed embedded_binary_plist hash and returns values
  # according to which field is passed.  Arguments passed are the hash
  # containing the value read from the 'ShadowHashData' key in the User's
  # plist, and the field to be read (one of 'entropy', 'salt', or 'iterations')
  def self.get_salted_sha512_pbkdf2(field, embedded_binary_plist, user_name = "")
    case field
    when 'salt', 'entropy'
      value = embedded_binary_plist['SALTED-SHA512-PBKDF2'][field]
      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)

View on GitHub (pinned to e227c27540)

Solutions

  1. Inspect the record: `dscl -plist . -read /Users/<name> ShadowHashData` and decode the plist to see which keys exist.
  2. Reset the user's password properly (`passwd` or Users & Groups) so macOS writes a complete SALTED-SHA512-PBKDF2 hash.
  3. Then re-run Puppet; the property compare will see a well-formed hash.
  4. If provisioning new users, provide the full 256-char PBKDF2 hash (salt+entropy+iterations) as the provider expects.
Defensive patterns

Strategy: try-catch

Validate before calling

# confirm the PBKDF2 keys exist before managing password on the user
require 'shellwords'
out = `dscl -plist . -read /Users/alice ShadowHashData 2>/dev/null`
# decode ShadowHashData plist and check ['SALTED-SHA512-PBKDF2']['salt'] and ['entropy'] are present

Type guard

def full_pbkdf2_record?(embedded_binary_plist)
  h = embedded_binary_plist['SALTED-SHA512-PBKDF2']
  h.is_a?(Hash) && !h['salt'].nil? && !h['entropy'].nil? && !h['iterations'].nil?
end

Try / catch

begin
  provider.password = pbkdf2_hash
rescue Puppet::Error => e
  raise unless e.message =~ /Invalid (salt|entropy) given for user/
  # record is malformed: reset via system tooling, then let Puppet converge next run
  Puppet::Util::Execution.execute(['passwd', resource[:name]], stdinfile: reset_file)
end

Prevention

When it happens

Trigger: Reading/comparing `password` on a macOS (10.8+) user whose hash was set as a different scheme (e.g., CRAM-MD5, SHA1 legacy, or a partially written PBKDF2 record), or a user record migrated/imported without full PBKDF2 data. Note 'iterations' uses Integer() and fails differently; only salt/entropy raise this.

Common situations: Users created by third-party MDM/imaging tools that write only some keys; accounts predating an OS upgrade; hand-edited plists; dscl cache serving stale/partial records.

Related errors


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