puppetlabs/puppet · error · Puppet::Error

OS X version #{self.class.get_os_version} does not allow cha

Error message

OS X version #{self.class.get_os_version} does not allow changing #{setter_method} using puppet

What it means

Raised by Puppet's macOS DirectoryService user provider when the manifest tries to change `home` or `uid` on an existing user. The provider defines setters for home/uid/gid/comment/shell, but for home and uid on a user that already has a value it refuses outright — Apple's DirectoryService semantics make these changes unsafe/unsupported from Puppet.

Source

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

  # that property and it needs changed (true here since all of these values
  # have a default that is set in the create method). We don't want to merge
  # in additional values if an incorrect value is set, we want to CHANGE it.
  # When using the -change argument in dscl, the old value needs to be passed
  # first (followed by the new value). Because of this, we get the current
  # value from the @property_hash variable and then use the value passed as
  # the new value. Because we're prefetching instances of the provider, it's
  # possible that the value determined at the start of the run may be stale
  # (i.e. someone changed the value by hand during a Puppet run) - if that's
  # the case we rescue the error from dscl and alert the user.
  #
  # In the event that the user doesn't HAVE a value for the attribute, the
  # provider should use the -create option with dscl to add the attribute value
  # for the user record
  %w[home uid gid comment shell].each do |setter_method|
    define_method("#{setter_method}=") do |value|
      if @property_hash[setter_method.intern]
        if %w[home uid].include?(setter_method)
          raise Puppet::Error, "OS X version #{self.class.get_os_version} does not allow changing #{setter_method} using puppet"
        end

        begin
          dscl '.', '-change', "/Users/#{resource.name}", self.class.ns_to_ds_attribute_map[setter_method.intern], @property_hash[setter_method.intern], value
        rescue Puppet::ExecutionFailure => e
          raise Puppet::Error, "Cannot set the #{setter_method} value of '#{value}' for user " \
                               "#{@resource.name} due to the following error: #{e.inspect}", e.backtrace
        end
      else
        begin
          dscl '.', '-create', "/Users/#{resource.name}", self.class.ns_to_ds_attribute_map[setter_method.intern], value
        rescue Puppet::ExecutionFailure => e
          raise Puppet::Error, "Cannot set the #{setter_method} value of '#{value}' for user " \
                               "#{@resource.name} due to the following error: #{e.inspect}", e.backtrace
        end
      end
    end
  end

View on GitHub (pinned to e227c27540)

Solutions

  1. Do not manage home/uid changes with Puppet on macOS — set them only at creation time and keep them stable afterwards.
  2. For a one-time migration, perform it out-of-band with `dscl . -change /Users/<name> UniqueID <old> <new>` plus the matching chown, then update the manifest to the new values.
  3. If the user record was created outside Puppet with wrong values, delete/recreate the record so Puppet's `create` path sets home/uid once.
  4. Scope the properties by OS: put home/uid inside a conditional so only non-Darwin platforms manage changes.

Example fix

# before
user { 'alice': ensure => present, home => '/Users/alice-new', uid => 2001 }
# after - create-time only on Darwin, migrate out-of-band
darwin_home_change = false  # handle via dscl + chown migration script
user { 'alice':
  ensure => present,
  uid    => darwin_home_change ? { true => 2001, default => undef },
}
Defensive patterns

Strategy: validation

Validate before calling

# manifest-side guard: only set home/uid at creation on Darwin
existing = `dscl . -read /Users/alice UniqueID 2>/dev/null`
# node-side: avoid changing these values at all
#   dscl . -change requires a manual migration

Type guard

def darwin_safe_properties?(current_uid, desired_uid, current_home, desired_home)
  (current_uid.nil? || current_uid == desired_uid) &&
    (current_home.nil? || current_home == desired_home)
end

Prevention

When it happens

Trigger: A `user` resource with a changed `home` or `uid` that already exists in the local directory (the @property_hash has a current value, so the '-change' branch runs and hits the guard). Also triggers if the provider's prefetch saw a value even though you expected creation.

Common situations: Renumbering UIDs during a migration; repointing home directories after storage changes; manifests reused from Linux where home/uid changes are routine; users pre-created by imaging/MDM so Puppet treats them as modifications rather than creations.

Related errors


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