puppetlabs/puppet · error · Puppet::Error
OS X versions > 10.7 require a Salted SHA512 PBKDF2 password
Error message
OS X versions > 10.7 require a Salted SHA512 PBKDF2 password hash of 256 characters. Please check your password and try again.
What it means
Raised by Puppet's macOS DirectoryService user provider on OS X newer than 10.7 when the `password` property value is not exactly 256 characters — the combined length of a Salted SHA-512 PBKDF2 hash (salt + entropy hex + iterations segments as the provider concatenates them). After the length check, assert_full_pbkdf2_password additionally verifies all three components are present.
Source
Thrown at lib/puppet/provider/user/directoryservice.rb:361
# If you thought GETTING a password was bad, try SETTING it. This method
# makes me want to cry. A thousand tears...
#
# I've been unsuccessful in tracking down a way to set the password for
# a user using dscl that DOESN'T require passing it as plaintext. We were
# also unable to get dsimport to work like this. Due to these downfalls,
# the sanest method requires opening the user's plist, dropping in the
# password hash, and serializing it back to disk. The problems with THIS
# method revolve around dscl. Any time you directly modify a user's plist,
# you need to flush the cache that dscl maintains.
def password=(value)
if self.class.get_os_version == '10.7'
if value.length != 136
raise Puppet::Error, "OS X 10.7 requires a Salted SHA512 hash password of 136 characters. Please check your password and try again."
end
else
if value.length != 256
raise Puppet::Error, "OS X versions > 10.7 require a Salted SHA512 PBKDF2 password hash of 256 characters. Please check your password and try again."
end
assert_full_pbkdf2_password
end
# Methods around setting the password on OS X are the ONLY methods that
# cannot use dscl (because the only way to set it via dscl is by passing
# a plaintext password - which is bad). Because of this, we have to change
# the user's plist directly. DSCL has its own caching mechanism, which
# means that every time we call dscl in this provider we're not directly
# changing values on disk (instead, those calls are cached and written
# to disk according to Apple's prioritization algorithms). When Puppet
# needs to set the password property on OS X > 10.6, the provider has to
# tell dscl to write its cache to disk before modifying the user's
# plist. The 'dscacheutil -flushcache' command does this. Another issue
# is how fast Puppet makes calls to dscl and how long it takes dscl to
# enter those calls into its cache. We have to sleep for 2 seconds before
# flushing the dscl cache to allow all dscl calls to get INTO the cacheView on GitHub (pinned to e227c27540)
Solutions
- Generate the full PBKDF2 form: iterations + 64-hex-char salt + 128-hex-char entropy, concatenated to exactly 256 characters.
- Extract a working example from an existing user: `dscl . -read /Users/<name> ShadowHashData` and hex-decode to confirm the layout.
- Version your password data in Hiera by OS version so 10.7 and 10.8+ hosts get the right format.
- Ensure assert_full_pbkdf2_password passes by including all three parts, not just the digest.
Example fix
# before (macOS 10.8+)
user { 'alice': ensure => present, password => 'abcdefgh<128 hex chars>' } # 136 chars, 10.7 format
# after - 256 chars: iterations(3) + salt(64 hex) + entropy(128 hex) ... total 256
user { 'alice': ensure => present, password => lookup('users::alice::pbkdf2_hash', Sensitive) } Defensive patterns
Strategy: type-guard
Validate before calling
raise 'expected 256 chars' unless hash.length == 256 parts = hash.partition_valid_pbkdf2 # salt(64) + entropy(128) + iterations present
Type guard
def valid_pbkdf2_256?(hash) hash.is_a?(String) && hash.length == 256 && hash.match?(/\A[0-9a-fA-F]+\z/) end
Prevention
- Verify hash length (256) and segment presence before assigning to `password`.
- After OS upgrades, regenerate hashes in the newer PBKDF2 format.
- Extract a known-good example from a working user's ShadowHashData as a template.
When it happens
Trigger: Managing `password` on macOS >= 10.8 with a 136-char 10.7-style salted SHA-512 hash, a plaintext string, or a PBKDF2 value missing a component so the concatenated form is the wrong length.
Common situations: Old manifests from 10.7 carried forward after an OS upgrade; hashes generated with wrong output length (e.g., truncated entropy); omitting the iterations segment.
Related errors
- Invalid #{field} given for user #{user_name}
- OS X 10.7 requires a Salted SHA512 hash password of 136 char
- Could not read password hash file at #{password_hash_file}
- OS X version #{self.class.get_os_version} does not allow cha
- puppet.plans/invalid-name
AI-assisted analysis of puppetlabs/puppet@e227c27540 (2026-08-21).
Data as JSON: /api/errors/665f68cc35168e3c.
Report an issue: GitHub.