jordansissel/fpm · error · FPM::InvalidPackageConfiguration

metacpan release query failed

Error message

metacpan release query failed

What it means

While resolving a Perl module to a downloadable tarball, fpm POSTs an Elasticsearch-style query to the metacpan API at /v1/release/_search to get the download_url for Distribution-VERSION. If the HTTP layer raises Net::HTTPServerException (any 4xx response), fpm logs the underlying error and re-raises FPM::InvalidPackageConfiguration with this message.

Source

Thrown at lib/fpm/package/cpan.rb:342

                 :distribution => distribution,
                 :version => cpan_version)

    # default to latest version unless we specify one
    if cpan_version.nil?
      self.version = "#{metadata["version"]}"
    else
      self.version = "#{cpan_version}"
    end

    # Search metacpan to get download URL for this version of the module
    metacpan_search_url = "#{attributes[:cpan_metacpan_api_url]}/v1/release/_search?_source=download_url"
    metacpan_search_query = {"query":{"term":{"name": "#{distribution}-#{self.version}" } } }.to_json
    begin
      search_response = httppost(metacpan_search_url,metacpan_search_query)
    rescue Net::HTTPServerException => e
      logger.error("metacpan release query failed.", :error => e.message,
                    :url => metacpan_search_url)
      raise FPM::InvalidPackageConfiguration, "metacpan release query failed"
    end

    data = search_response.body
    release_metadata = JSON.parse(data)

    download_url = release_metadata['hits']['hits'][0]['_source']['download_url']
    download_path = URI.parse(download_url).path
    tarball = File.basename(download_path)

    url_base = "http://www.cpan.org/"
    url_base = "#{attributes[:cpan_mirror]}" if !attributes[:cpan_mirror].nil?

    url = "#{url_base}#{download_path}"
    logger.debug("Fetching perl module", :url => url)

    begin
      response = httpfetch(url)
    rescue Net::HTTPServerException => e

View on GitHub (pinned to b6d77ba72a)

Solutions

  1. Reproduce the failing request outside fpm: curl -s -X POST 'https://fastapi.metacpan.org/v1/release/_search?_source=download_url' -H 'Content-Type: application/json' -d '{"query":{"term":{"name":"Foo-1.00"}}}' and inspect the status code
  2. Check that Distribution-VERSION actually exists on metacpan (search the module on metacpan.org); a wrong --version produces a name term with no release
  3. Verify --cpan-metacpan-api-url; unset it or set it to https://fastapi.metacpan.org
  4. If a proxy is involved, configure correct proxy env vars (http_proxy/https_proxy) so the POST is not rejected with 4xx
  5. Update fpm if you run an old release that uses a retired metacpan endpoint

Example fix

# before
fpm -s cpan -t deb Foo --cpan-metacpan-api-url https://metacpan.local   # 404 -> metacpan release query failed

# after
fpm -s cpan -t deb Foo                          # default URL
fpm -s cpan -t deb Foo --cpan-metacpan-api-url https://fastapi.metacpan.org
Defensive patterns

Strategy: retry

Validate before calling

require 'net/http'
uri = URI('https://fastapi.metacpan.org/v1/release/_search?_source=download_url')
begin
  resp = Net::HTTP.post(uri, { query: { term: { name: 'Foo-1.00' } } }.to_json,
                        'Content-Type' => 'application/json')
  abort "metacpan returned HTTP #{resp.code}" unless resp.code == '200'
rescue SocketError => e
  abort "cannot resolve metacpan: #{e.message}"
end

Try / catch

require 'net/http'

3.times do |attempt|
  begin
    pkg = FPM::Package::CPAN.new
    pkg.input('Foo')
    break
  rescue FPM::InvalidPackageConfiguration => e
    raise if attempt == 2 || !e.message.include?('metacpan release query failed')
    sleep(2**attempt)   # metacpan 4xx: back off for 429, recheck URL for 4xx
    warn "retry #{attempt + 1}/3 after metacpan error"
  end
end

Prevention

When it happens

Trigger: Calling fpm -s cpan (input/download path) when metacpan answers 4xx to the release _search POST: 404 from an outdated/changed API base URL (--cpan-metacpan-api-url pointing at a wrong or proxied host), 400 for a malformed query, or a corporate proxy returning 403/407. Only HTTP 4xx raises here; DNS failures and connection refused raise different errors.

Common situations: Custom --cpan-metacpan-api-url typo or stale self-hosted metacpan instance; metacpan API schema/endpoint changes after an upgrade; proxy or captive-portal interception of api.metacpan.org; requests behind flaky networks returning 429.

Related errors


AI-assisted analysis of jordansissel/fpm@b6d77ba72a (2026-08-21). Data as JSON: /api/errors/c889c103d690e5a6. Report an issue: GitHub.