puppetlabs/puppet · error · Puppet::Error

e.message

Error message

e.message

What it means

A pass-through error from the rpm provider's latest: the version of the source RPM is read with 'rpm -q -p <source>' and any Puppet::ExecutionFailure is re-raised as Puppet::Error carrying the original rpm message and backtrace. The message you see is rpm's own complaint - typically 'open of <file> failed' or 'not an rpm package'.

Source

Thrown at lib/puppet/provider/package/rpm.rb:121

      end
    end
    @property_hash.update(self.class.nevra_to_multiversion_hash(output))

    @property_hash.dup
  end

  # Here we just retrieve the version from the file specified in the source.
  def latest
    source = @resource[:source]
    unless source
      @resource.fail _("RPMs must specify a package source")
    end

    cmd = [command(:rpm), "-q", "--qf", self.class::NEVRA_FORMAT.to_s, "-p", source]
    h = self.class.nevra_to_multiversion_hash(execute(cmd))
    h[:ensure]
  rescue Puppet::ExecutionFailure => e
    raise Puppet::Error, e.message, e.backtrace
  end

  def install
    source = @resource[:source]
    unless source
      @resource.fail _("RPMs must specify a package source")
    end

    version = @property_hash[:ensure]

    # RPM gets upset if you try to install an already installed package
    return if @resource.should(:ensure) == version || (@resource.should(:ensure) == :latest && version == latest)

    flag = ["-i"]
    flag = ["-U", "--oldpackage"] if version && (version != :absent && version != :purged)
    flag += install_options if resource[:install_options]
    rpm flag, source
  end

View on GitHub (pinned to e227c27540)

Solutions

  1. Run 'rpm -q -p <source>' yourself - the raised message is exactly rpm's complaint; fix the path or file accordingly
  2. Validate the file: 'file <source>' should report 'RPM v3'; re-download if size/checksum is off
  3. Ensure the puppet process can read the file (permissions, SELinux labels on the staging directory)
  4. If source is a URL rpm struggles with, stage it locally with a file resource first and reference the local path

Example fix

// before - typo'd/stale source path, rpm -q -p fails
package { 'mysvc':
  ensure   => latest,
  provider => rpm,
  source   => '/opt/pkgs/mysvc-1.0.1-1.el7.rpm ',
}
// after - staged with checksums, correct path, explicit ordering
file { '/opt/pkgs/mysvc-1.0.1-1.el7.rpm':
  ensure => file,
  source => 'puppet:///modules/profile/mysvc-1.0.1-1.el7.rpm',
}
package { 'mysvc':
  ensure   => latest,
  provider => rpm,
  source   => '/opt/pkgs/mysvc-1.0.1-1.el7.rpm',
  require  => File['/opt/pkgs/mysvc-1.0.1-1.el7.rpm'],
}
Defensive patterns

Strategy: validation

Validate before calling

# Ruby: check the source is a readable RPM before letting latest query it
RPM_MAGIC = "\xED\xAB\xEE\xDB".b
def valid_rpm_file?(path)
  File.readable?(path) && File.open(path, 'rb') { |f| f.read(4) == RPM_MAGIC }
end

Try / catch

begin
  latest_ver = provider.latest
rescue Puppet::Error => e
  raise Puppet::Error, "source rpm for #{resource[:name]} unusable: #{e.message}" if e.message =~ /open of .* failed|not an rpm/i
  raise
end

Prevention

When it happens

Trigger: package { 'x': provider => rpm, ensure => latest, source => '/tmp/x.rpm' } where the file is missing, unreadable, truncated, not actually an rpm, or a URL rpm cannot fetch. Also fires for ensure => <version> comparisons that consult latest. The query at lib/puppet/provider/package/rpm.rb:117 fails and the rescue at :120 re-raises.

Common situations: Typo'd source paths; files misnamed .rpm (actually deb/gem); partially downloaded rpms; remote source URLs requiring auth; puppet agent lacking read permission or SELinux context on the file.

Related errors


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