puppetlabs/puppet · error · Puppet::Error

No such group %{group}

Error message

No such group %{group}

What it means

Puppet::Util::SUIDManager.change_group (suidmanager.rb:103) resolves the group via convert_xid(:gid, group) (Integers pass through; names go through Puppet::Util.gid -> getgrnam/getgrgid lookups) and raises Puppet::Error 'No such group <group>' when the result is falsy. Reached from change_privileges/asuser, which back the 'run as another user/group' behavior of exec resources and privilege-dropping code. In the current code the unresolvable-name case usually raises the earlier 'Invalid group' from convert_xid, so this line is the backstop when the gid lookup yields nil/false without that raise (or on older Puppet revisions).

Source

Thrown at lib/puppet/util/suidmanager.rb:103

  def change_privileges(uid = nil, gid = nil, permanently = false)
    return unless uid or gid

    unless gid
      uid = convert_xid(:uid, uid)
      gid = Etc.getpwuid(uid).gid
    end

    change_group(gid, permanently)
    change_user(uid, permanently) if uid
  end
  module_function :change_privileges

  # Changes the egid of the process if `permanently` is not set, otherwise
  # changes gid. This method will fail if used on Windows, or attempting to
  # change to a different gid without root.
  def change_group(group, permanently = false)
    gid = convert_xid(:gid, group)
    raise Puppet::Error, _("No such group %{group}") % { group: group } unless gid

    return if Process.egid == gid

    if permanently
      Process::GID.change_privilege(gid)
    else
      Process.egid = gid
    end
  end
  module_function :change_group

  # As change_group, but operates on uids. If changing user permanently,
  # supplementary groups will be set the to default groups for the new uid.
  def change_user(user, permanently = false)
    uid = convert_xid(:uid, user)
    raise Puppet::Error, _("No such user %{user}") % { user: user } unless uid

    return if Process.euid == uid

View on GitHub (pinned to e227c27540)

Solutions

  1. Ensure the group exists first: add a group resource and make the exec depend on it (require => Group['myapp']).
  2. Verify resolution on the host: getent group myapp (covers NSS/LDAP) or Puppet::Etc.getgrnam in Ruby.
  3. Pass the numeric gid when the name is not stable across systems.
  4. Rescue Puppet::Error around privilege change and report both the group and the result of getent for the node.

Example fix

// before
exec { 'migrate':
  command => '/usr/local/bin/migrate',
  group   => 'myapp',   # group not yet created when this runs
}

// after
group { 'myapp': ensure => present }
exec { 'migrate':
  command => '/usr/local/bin/migrate',
  group   => 'myapp',
  require => Group['myapp'],
}
Defensive patterns

Strategy: validation

Validate before calling

gid = group.is_a?(Integer) ? group : Puppet::Util::POSIX.gid(group)
raise ArgumentError, "group #{group} does not resolve on this node (check getent group)" if gid.nil?
Puppet::Util::SUIDManager.change_group(group)

Try / catch

begin
  Puppet::Util::SUIDManager.change_group(group, permanently)
rescue Puppet::Error => e
  raise unless e.message =~ /No such group/
  raise Puppet::Error, "#{e.message} — is the group resource realized and NSS/LDAP reachable?"
end

Prevention

When it happens

Trigger: change_privileges(uid, 'myapp') when group myapp does not exist yet; change_group(12345) for a gid absent from /etc/group; exec resource with group => before the group resource has been realized; NSS/LDAP group resolution broken so getgrnam returns nil.

Common situations: Ordering: an exec that drops to a service group runs before the package creating that group; typos in group names in manifests; hosts not joined to the directory providing the group; containers missing the group entry the manifest assumes.

Related errors


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