puppetlabs/puppet · error · LoadError

The 'getgrouplist' method is not available

Error message

The 'getgrouplist' method is not available

What it means

Puppet::Util::POSIX#get_groups_list (posix.rb:39) raises LoadError when Puppet::FFI::POSIX::Functions does not respond to getgrouplist, i.e. the FFI binding for getgrouplist(3) is absent (platform without the libc call, ffi gem missing/broken, or restricted load). Important context: the public caller groups_of (posix.rb:15-26) rescues StandardError and LoadError, logs 'Falling back to Puppet::Etc.group', and iterates the group database instead, so seeing this error escape means someone called the private helper directly or the fallback path itself is broken.

Source

Thrown at lib/puppet/util/posix.rb:39

        groups = []
        Puppet::Etc.group do |group|
          groups << group.name if group.mem.include?(user)
        end
      end

      uniq_groups = groups.uniq
      if uniq_groups != groups
        Puppet.debug(_('Removing any duplicate group entries'))
      end

      uniq_groups
    end

    private

    def get_groups_list(user)
      raise LoadError, "The 'getgrouplist' method is not available" unless Puppet::FFI::POSIX::Functions.respond_to?(:getgrouplist)

      user_gid = Puppet::Etc.getpwnam(user).gid
      ngroups = Puppet::FFI::POSIX::Constants::MAXIMUM_NUMBER_OF_GROUPS

      loop do
        FFI::MemoryPointer.new(:int) do |ngroups_ptr|
          FFI::MemoryPointer.new(:uint, ngroups) do |groups_ptr|
            old_ngroups = ngroups
            ngroups_ptr.write_int(ngroups)

            if Puppet::FFI::POSIX::Functions.getgrouplist(user, user_gid, groups_ptr, ngroups_ptr) != -1
              groups_gids = groups_ptr.get_array_of_uint(0, ngroups_ptr.read_int)

              result = []
              groups_gids.each do |group_gid|
                group_info = Puppet::Etc.getgrgid(group_gid)
                result |= [group_info.name] if group_info.mem.include?(user)
              end

View on GitHub (pinned to e227c27540)

Solutions

  1. Use the public Puppet::Util::POSIX.groups_of(user), which already falls back to Puppet::Etc.group iteration.
  2. Ensure the ffi gem is installed and loadable: gem install ffi; ruby -e "require 'ffi'".
  3. On the problem host, verify the symbol exists: ruby -e "require 'puppet/ffi/posix'; p Puppet::FFI::POSIX::Functions.respond_to?(:getgrouplist)".
  4. If the platform genuinely lacks getgrouplist (e.g., Windows), branch to Puppet::Util::Windows or Etc-based enumeration instead of the FFI path.

Example fix

// before
groups = obj.send(:get_groups_list, user) # bypasses the guarded path, raises LoadError

// after
groups = Puppet::Util::POSIX.groups_of(user) # FFI path with automatic Etc.group fallback
Defensive patterns

Strategy: validation

Validate before calling

require 'puppet/ffi/posix' rescue nil
ffi_ok = defined?(Puppet::FFI::POSIX::Functions) && Puppet::FFI::POSIX::Functions.respond_to?(:getgrouplist)

Try / catch

begin
  groups = Puppet::Util::POSIX.groups_of(user)
rescue LoadError => e
  Puppet.warning("FFI group lookup unavailable (#{e.message}); using Etc fallback")
  groups = Puppet::Etc.group.select { |g| g.mem.include?(user) }.map(&:name)
end

Prevention

When it happens

Trigger: Calling get_groups_list/send(:get_groups_list, user) directly on Windows (no getgrouplist), on a platform where the ffi gem failed to install, or when libffi cannot bind the symbol (hardened libc, missing headers at gem build time). Calling groups_of on such a platform only logs a debug fallback, it does not raise.

Common situations: Running Puppet code on unsupported/minimal containers (alpine without libffi), FFI gem compiled against an incompatible libc after a system upgrade, custom user/group providers invoking POSIX groups handling outside Puppet's own guarded path.

Related errors


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