{"record":{"id":"e467ee39296d5aa1","repo":"puppetlabs/puppet","slug":"os-x-version-self-class-get-os-version-does-not","errorCode":null,"errorMessage":"OS X version #{self.class.get_os_version} does not allow changing #{setter_method} using puppet","messagePattern":"OS X version #(.+?) does not allow changing #(.+?) using puppet","errorType":"exception","errorClass":"Puppet::Error","httpStatus":null,"severity":"error","filePath":"lib/puppet/provider/user/directoryservice.rb","lineNumber":455,"sourceCode":"  # that property and it needs changed (true here since all of these values\n  # have a default that is set in the create method). We don't want to merge\n  # in additional values if an incorrect value is set, we want to CHANGE it.\n  # When using the -change argument in dscl, the old value needs to be passed\n  # first (followed by the new value). Because of this, we get the current\n  # value from the @property_hash variable and then use the value passed as\n  # the new value. Because we're prefetching instances of the provider, it's\n  # possible that the value determined at the start of the run may be stale\n  # (i.e. someone changed the value by hand during a Puppet run) - if that's\n  # the case we rescue the error from dscl and alert the user.\n  #\n  # In the event that the user doesn't HAVE a value for the attribute, the\n  # provider should use the -create option with dscl to add the attribute value\n  # for the user record\n  %w[home uid gid comment shell].each do |setter_method|\n    define_method(\"#{setter_method}=\") do |value|\n      if @property_hash[setter_method.intern]\n        if %w[home uid].include?(setter_method)\n          raise Puppet::Error, \"OS X version #{self.class.get_os_version} does not allow changing #{setter_method} using puppet\"\n        end\n\n        begin\n          dscl '.', '-change', \"/Users/#{resource.name}\", self.class.ns_to_ds_attribute_map[setter_method.intern], @property_hash[setter_method.intern], value\n        rescue Puppet::ExecutionFailure => e\n          raise Puppet::Error, \"Cannot set the #{setter_method} value of '#{value}' for user \" \\\n                               \"#{@resource.name} due to the following error: #{e.inspect}\", e.backtrace\n        end\n      else\n        begin\n          dscl '.', '-create', \"/Users/#{resource.name}\", self.class.ns_to_ds_attribute_map[setter_method.intern], value\n        rescue Puppet::ExecutionFailure => e\n          raise Puppet::Error, \"Cannot set the #{setter_method} value of '#{value}' for user \" \\\n                               \"#{@resource.name} due to the following error: #{e.inspect}\", e.backtrace\n        end\n      end\n    end\n  end","sourceCodeStart":437,"sourceCodeEnd":473,"githubUrl":"https://github.com/puppetlabs/puppet/blob/e227c27540975c25aa22d533a52424a9d2fc886a/lib/puppet/provider/user/directoryservice.rb#L437-L473","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","solutions":["Do not manage home/uid changes with Puppet on macOS — set them only at creation time and keep them stable afterwards.","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.","If the user record was created outside Puppet with wrong values, delete/recreate the record so Puppet's `create` path sets home/uid once.","Scope the properties by OS: put home/uid inside a conditional so only non-Darwin platforms manage changes."],"exampleFix":"# before\nuser { 'alice': ensure => present, home => '/Users/alice-new', uid => 2001 }\n# after - create-time only on Darwin, migrate out-of-band\ndarwin_home_change = false  # handle via dscl + chown migration script\nuser { 'alice':\n  ensure => present,\n  uid    => darwin_home_change ? { true => 2001, default => undef },\n}","handlingStrategy":"validation","validationCode":"# manifest-side guard: only set home/uid at creation on Darwin\nexisting = `dscl . -read /Users/alice UniqueID 2>/dev/null`\n# node-side: avoid changing these values at all\n#   dscl . -change requires a manual migration","typeGuard":"def darwin_safe_properties?(current_uid, desired_uid, current_home, desired_home)\n  (current_uid.nil? || current_uid == desired_uid) &&\n    (current_home.nil? || current_home == desired_home)\nend","tryCatchPattern":null,"preventionTips":["Treat home/uid as immutable on macOS; plan migrations as out-of-band dscl+chown scripts.","Pre-create users via Puppet (not imaging tools) so creation-time values stick.","Scope home/uid properties to non-Darwin platforms in shared profiles."],"tags":["macos","user-management","dscl","puppet"],"backgroundTag":"unsupported-attribute-change","analyzedSha":"e227c27540975c25aa22d533a52424a9d2fc886a","analyzedAt":"2026-08-21T20:49:46.650Z","schemaVersion":2},"datasetVersion":"2026-08-21T23:17:16.201Z"}