{"record":{"id":"6c9db931d27f9682","repo":"puppetlabs/puppet","slug":"could-not-list-gems-detail","errorCode":null,"errorMessage":"Could not list gems: %{detail}","messagePattern":"Could not list gems: %(.+?)","errorType":"exception","errorClass":"Puppet::Error","httpStatus":null,"severity":"error","filePath":"lib/puppet/provider/package/gem.rb","lineNumber":126,"sourceCode":"\n    if options[:local]\n      command_options << \"--local\"\n    else\n      command_options << \"--remote\"\n    end\n    if options[:source]\n      command_options << \"--source\" << options[:source]\n    end\n    name = options[:justme]\n    if name\n      command_options << '\\A' + name + '\\z'\n    end\n\n    begin\n      list = execute_gem_command(options[:command], command_options).lines\n                                                                    .filter_map { |set| gemsplit(set) }\n    rescue Puppet::ExecutionFailure => detail\n      raise Puppet::Error, _(\"Could not list gems: %{detail}\") % { detail: detail }, detail.backtrace\n    end\n\n    if options[:justme]\n      list.shift\n    else\n      list\n    end\n  end\n\n  def self.gemsplit(desc)\n    # `gem list` when output console has a line like:\n    # *** LOCAL GEMS ***\n    # but when it's not to the console that line\n    # and all blank lines are stripped\n    # so we don't need to check for them\n\n    if desc =~ /^(\\S+)\\s+\\((.+)\\)/\n      gem_name = Regexp.last_match(1)","sourceCodeStart":108,"sourceCodeEnd":144,"githubUrl":"https://github.com/puppetlabs/puppet/blob/e227c27540975c25aa22d533a52424a9d2fc886a/lib/puppet/provider/package/gem.rb#L108-L144","documentation":"gem.rb:126: the provider lists installed/available gems by shelling out (execute_gem_command, e.g. `gem list ...` or `gem list --remote --source ...`) and wrapping the run; when the gem command exits non-zero (Puppet::ExecutionFailure) it re-raises as Puppet::Error 'Could not list gems: %{detail}' with the command output attached. The listing is what powers instances, prefetch and query, so the error aborts gem package management for the run.","triggerScenarios":"Any gem package resource (or `puppet resource package provider=gem`) on a node where the configured gemcmd fails: bad gem executable path (wrong ruby via rbenv/rvm shims without the right environment), corrupted gem home/cache permissions, or a remote `--source` that is unreachable/has an expired TLS cert when ensure => latest triggers a remote list.","commonSituations":"Multi-ruby hosts where puppet picks a different ruby's gem than the app uses; ~/.gem owned by root after someone ran gem with sudo; private gem sources (Gemfury/artifactory) with expired certs or unreachable hosts; gem binary removed during a ruby upgrade.","solutions":["Reproduce as the puppet user with the same binary: `<gemcmd> list` — read %{detail} for the real stderr.","Pin the correct ruby/gem explicitly: set `gemcmd`/`rubygem` command or use `provider => gem` with `command_options`/puppet settings so the intended gem binary is used.","Fix environment issues: correct GEM_HOME/GEM_PATH, repair ownership of the gem home, or update CA certs / credentials for the remote source.","If a remote source is flaky, consider mirroring gems internally instead of ensure => latest against the internet."],"exampleFix":"# before\npackage { 'bundler': ensure => installed, provider => 'gem' } # picks wrong rvm ruby\n\n# after\npackage { 'bundler': ensure => installed, provider => 'gem', install_options => ['--bindir', '/usr/local/bin'] }\n# plus ensure puppet's gemcmd points at the system ruby (e.g. /usr/bin/gem), not an rvm shim","handlingStrategy":"try-catch","validationCode":"# verify the gem binary works as the puppet user\ncmd = provider_gemcmd # e.g. /opt/ruby/bin/gem\nout = `#{cmd} list 2>&1`\nfail \"gem broken: #{out}\" unless $?.success?","typeGuard":null,"tryCatchPattern":"begin\n  Puppet::Type.type(:package).provider(:gem).instances\nrescue Puppet::Error => e\n  raise unless e.message =~ /Could not list gems/\n  # skip gem enumeration this run rather than failing the whole catalog\n  Puppet.err(e.message); []\nend","preventionTips":["Pin gemcmd to an absolute, verified gem binary per node (no rvm/rbenv shims on the agent PATH).","Check GEM_HOME/GEM_PATH ownership after any sudo gem usage.","Mirror gem sources internally and monitor their TLS certs if you use ensure => latest."],"tags":["puppet","rubygems","gem","packages","command-execution"],"backgroundTag":"command-execution-failed","analyzedSha":"e227c27540975c25aa22d533a52424a9d2fc886a","analyzedAt":"2026-08-21T20:49:46.650Z","schemaVersion":2},"datasetVersion":"2026-08-21T23:17:16.201Z"}