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.

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.

Appendix: 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)