puppetlabs/puppet · error · Puppet::Error
puppet:// URLs are not supported as gem sources
Error message
puppet:// URLs are not supported as gem sources
What it means
gem.rb:240: while building gem install options, the provider parses the resource's source as a URI; a scheme of 'puppet' (puppet:// URLs from the file server) is explicitly rejected with Puppet::Error, because gem cannot fetch packages from Puppet's fileserver. Supported shapes are no scheme (local path), file:// paths, absolute paths, or a remote repository URL passed via --source.
Source
Thrown at lib/puppet/provider/package/gem.rb:240
end
source = resource[:source]
if source
begin
uri = URI.parse(source)
rescue => detail
self.fail Puppet::Error, _("Invalid source '%{uri}': %{detail}") % { uri: uri, detail: detail }, detail
end
case uri.scheme
when nil
# no URI scheme => interpret the source as a local file
command_options << source
when /file/i
command_options << uri.path
when 'puppet'
# we don't support puppet:// URLs (yet)
raise Puppet::Error, _("puppet:// URLs are not supported as gem sources")
else
# check whether it's an absolute file path to help Windows out
if Puppet::Util.absolute_path?(source)
command_options << source
else
# interpret it as a gem repository
command_options << "--source" << source.to_s << resource[:name]
end
end
else
command_options << resource[:name]
end
output = self.class.execute_gem_command(command, command_options)
# Apparently some gem versions don't exit non-0 on failure.
self.fail _("Could not install: %{output}") % { output: output.chomp } if output.include?("ERROR")
end
View on GitHub (pinned to e227c27540)
Solutions
- Stage the .gem with a file resource from puppet://, then pass the local path as the gem package's source.
- Or serve gems from a real repository (file:// directory, https internal geminabox/artifactory) and point source at it.
- Never use a puppet:// URL directly as a gem source — the provider rejects it by design.
Example fix
# before
package { 'foo': ensure => installed, provider => 'gem', source => 'puppet:///modules/gems/foo-1.0.gem' }
# after
file { '/tmp/foo-1.0.gem': source => 'puppet:///modules/gems/foo-1.0.gem', before => Package['foo'] }
package { 'foo': ensure => installed, provider => 'gem', source => '/tmp/foo-1.0.gem' } Defensive patterns
Strategy: validation
Validate before calling
# reject puppet:// schemes before declaring the resource uri = URI.parse(source.to_s) fail 'gem sources cannot be puppet:// — stage the file first' if uri.scheme == 'puppet'
Type guard
def valid_gem_source?(s) u = URI.parse(s.to_s) u.scheme.nil? || u.scheme =~ /file/i || %w[http https].include?(u.scheme) rescue URI::InvalidURIError false end
Try / catch
begin
provider.install
rescue Puppet::Error => e
raise unless e.message.include?('puppet:// URLs are not supported')
# stage from the fileserver, then install from the local copy
stage(source); resource[:source] = local_path; retry
end Prevention
- Standardize on file-resource staging for gem artifacts served by Puppet.
- Keep an internal gem server (geminabox/artifactory) for air-gapped installs instead of fileserver URLs.
- Lint package sources: any puppet:// URL on a gem package is a config error by definition.
When it happens
Trigger: package { X: provider => gem, source => 'puppet:///modules/gems/x-1.0.gem' } — any attempt to install a .gem directly from the module mount. The URI parses fine (it was already validated as a URI), only the scheme check fails.
Common situations: Teams air-gapping gems try to serve them from the Puppet fileserver the same way they stage debs/rpms; converting a file { source => 'puppet://...' } pattern to package resources without adapting the URL.
Related errors
- Could not list gems: %{detail}
- The aix provider can only be used by root
- Could not list installed Packages: %{detail}
- /etc/apt/sources.list contains a cdrom source; not installin
- Could not find package %{name}
AI-assisted analysis of puppetlabs/puppet@e227c27540 (2026-08-21).
Data as JSON: /api/errors/516624ccd3a4f3f1.
Report an issue: GitHub.