puppetlabs/puppet · error · RuntimeError

Could not download module: %{message}

Error message

Could not download module: %{message}

What it means

download_tarballs fetches each release tarball, either from a local path (release[:tarball]) or from the Forge via forge.retrieve. Any OpenURI::HTTPError during that fetch — 404, 403, 429, 5xx, or a proxy/TLS problem that surfaces as an HTTP error — is re-raised as a RuntimeError whose message embeds the HTTP error, with the original backtrace preserved. It is a transport failure, not a dependency-resolution failure.

Source

Thrown at lib/puppet/module_tool/shared_behaviors.rb:173

      }
    end
    dependencies.each do |mod|
      deps = @remote["#{mod[:module]}@#{mod[:version][:vstring]}"].sort_by(&:first)
      mod[:dependencies] = resolve_constraints(deps, source + [{ :name => mod[:module], :version => mod[:version][:vstring] }], seen, :install)
    end unless @ignore_dependencies
    dependencies
  end

  def download_tarballs(graph, default_path, forge)
    graph.map do |release|
      begin
        if release[:tarball]
          cache_path = Pathname(release[:tarball])
        else
          cache_path = forge.retrieve(release[:file])
        end
      rescue OpenURI::HTTPError => e
        raise RuntimeError, _("Could not download module: %{message}") % { message: e.message }, e.backtrace
      end

      [
        { (release[:path] ||= default_path) => cache_path },
        *download_tarballs(release[:dependencies], default_path, forge)
      ]
    end.flatten
  end

  def forced?
    options[:force]
  end

  def add_module_name_constraints_to_graph(graph)
    # Puppet modules are installed by "module name", but resolved by
    # "full name" (including namespace).  So that we don't run into
    # problems at install time, we should reject any solution that
    # depends on multiple nodes with the same "module name".

View on GitHub (pinned to e227c27540)

Solutions

  1. Retry after confirming Forge health (status.puppet.com) — transient 5xx/429 responses are the most common cause.
  2. Verify the release exists: curl 'https://forgeapi.puppet.com/v3/releases?module=author-mod' or open the module page on forge.puppet.com.
  3. Fix the network path: set https_proxy/no_proxy correctly for the puppet process, keep the CA bundle current, and exempt forgeapi.puppet.com from SSL inspection.
  4. Pin versions known to exist and cache them locally (r10k/Puppetfile with a mirror) so installs survive Forge problems.

Example fix

# before
$ puppet module install puppetlabs-apt
Error: Could not download module: 503 Service Unavailable

# after — correct proxy env and retry with backoff
$ export no_proxy=forgeapi.puppet.com,forge.puppet.com
$ for i in 1 2 3; do puppet module install puppetlabs-apt && break; sleep $((i*30)); done
Defensive patterns

Strategy: retry

Validate before calling

require 'open-uri'
# pre-flight: the tarball URL must respond before you install
url = 'https://forgeapi.puppet.com/v3/files/puppetlabs-apt-9.0.0.tar.gz'
OpenURI.open_uri(url) { |f| puts 'ok: ' + f.status.first }

Try / catch

tries = 0
begin
  forge.retrieve(release[:file])
rescue OpenURI::HTTPError => e
  tries += 1
  retry if tries < 3 && e.message =~ /503|429/
  raise RuntimeError, "module download failed after #{tries} tries: #{e.message}"
end

Prevention

When it happens

Trigger: 'puppet module install' when forge.retrieve gets an HTTP error: the tarball URL 404s (release deleted), the Forge rate-limits (429/403), a proxy intercepts forgeapi.puppet.com, or a custom forge baseurl points at a server that errors.

Common situations: Forge outages or rate limiting during mass CI installs; deprecated modules with releases removed; corporate proxies or SSL-inspection appliances breaking the download; private Forge mirrors missing the requested release.

Related errors


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